collect2源码分析(gcc 3.0-core)
1.collect2的作用
请参考
(程序员的自我修养:链接、装载
与库)
在<<程序员的自我修养:链接、装载与库>>说的很清楚,collect2基本上是ld的包装,只在极少数
系统中做额外的处理,因此我们不分析那些很少用到的功能了。
2.从例子开始
写一个HelloWorld程序,看看collect2是如何被调用的
1.c
#include
int main()
{
printf("Hello World!\n");
return 0;
}
[root@mail ~/gcc-3.0/build/gcc]# gcc -v 1.c
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.2/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --
infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking
--with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux
Thread model: posix
gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/cc1 -lang-c -v -D__GNUC__=3 -
D__GNUC_MINOR__=2 -D__GNUC_PATCHLEVEL__=2 -D__GXX_ABI_VERSION=102 -D__ELF__ -Dunix
-D__gnu_linux__ -Dlinux -D__ELF__ -D__unix__ -D__gnu_linux__ -D__linux__ -D__unix
-D__linux -Asystem=posix -D__NO_INLINE__ -D__STDC_HOSTED__=1 -Acpu=i386 -
Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i386__ 1.c -quiet -dumpbase 1.c
-version -o /tmp/ccRpApN7.s
GNU CPP version 3.2.2 20030222 (Red Hat Linux 3.2.2-5) (cpplib) (i386 Linux/ELF)
GNU C version 3.2.2 20030222 (Red Hat Linux 3.2.2-5) (i386-redhat-linux)
compiled by GNU C version 3.2.2 20030222 (Red Hat Linux 3.2.2-5).
ignoring nonexistent directory "/usr/i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/include
/usr/include
End of search list.
as -V -Qy -o /tmp/ccYArP28.o /tmp/ccRpApN7.s
GNU assembler version 2.18 (i686-pc-linux-gnu) using BFD version (GNU Binutils)
2.18
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/collect2 --eh-frame-hdr -m elf_i386 -
dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/../../../crt1.o /usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/../../../crti.o /usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtbegin.o -
L/usr/lib/gcc-lib/i386-redhat-linux/3.2.2 -L/usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/../../.. /tmp/ccYArP28.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtend.o /usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/../../../crtn.o
[root@mail ~/gcc-3.0/build/gcc]#
我们看到,用cc1将1.c编译成汇编文件,再用as将汇编文件编译成目标文件后,gcc调用collect2连
接目标文件。
3.main
collect2的源程序在gcc目录下collect2.c,对于没有定义的条件预处理,我们使用//将其注释掉
了,以免干扰分析。
int
main (argc, argv)
int argc;
char *argv[];
{
const char *ld_suffix = "ld";
const char *full_ld_suffix = ld_suffix;
const char *real_ld_suffix = "real-ld";
const char *collect_ld_suffix = "collect-ld";
const char *nm_suffix = "nm";
const char *full_nm_suffix = nm_suffix;
const char *gnm_suffix = "gnm";
const char *full_gnm_suffix = gnm_suffix;
//#ifdef LDD_SUFFIX
// const char *ldd_suffix = LDD_SUFFIX;
// const char *full_ldd_suffix = ldd_suffix;
//#endif
const char *strip_suffix = "strip";
const char *full_strip_suffix = strip_suffix;
const char *gstrip_suffix = "gstrip";
const char *full_gstrip_suffix = gstrip_suffix;
const char *arg;
FILE *outf;
//#ifdef COLLECT_EXPORT_LIST
// FILE *exportf;
//#endif
const char *ld_file_name;
const char *p;
char **c_argv;
const char **c_ptr;
char **ld1_argv;
const char **ld1;
char **ld2_argv;
const char **ld2;
char **object_lst;
const char **object;
int first_file;
int num_c_args = argc+9;
//#if defined (COLLECT2_HOST_INITIALIZATION)
/* Perform system dependent initialization, if neccessary. */
// COLLECT2_HOST_INITIALIZATION;
//#endif
#ifdef SIGCHLD
/* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
receive the signal. A different setting is inheritable */
signal (SIGCHLD, SIG_DFL);
#endif
/* LC_CTYPE determines the character set used by the terminal so it has be set
to output messages correctly. */
#ifdef HAVE_LC_MESSAGES
setlocale (LC_CTYPE, "");
setlocale (LC_MESSAGES, "");
#else
setlocale (LC_ALL, "");
#endif
(void) bindtextdomain (PACKAGE, localedir);
(void) textdomain (PACKAGE);
以上主要定义了一些collect2要用到的程序名,然后是标准的初始化流程。
4.-debug
/* Do not invoke xcalloc before this point, since locale needs to be
set first, in case a diagnostic is issued. */
ld1 = (const char **)(ld1_argv = (char **) xcalloc(sizeof (char *),
argc+3));//<<<<传给ld
ld2 = (const char **)(ld2_argv = (char **) xcalloc(sizeof (char *), argc+10));
object = (const char **)(object_lst = (char **) xcalloc(sizeof (char *),
argc));//object_lst<<<<<<<目标文件
//#ifdef DEBUG
// debug = 1;
//#endif
/* Parse command line early for instances of -debug. This allows
the debug flag to be set before functions like find_a_file()
are called. */
{
int i;
for (i = 1; argv[i] != NULL; i ++)
if (! strcmp (argv[i], "-debug"))
debug = 1;
vflag = debug;
}
//#ifndef DEFAULT_A_OUT_NAME
output_file = "a.out";
//#else
// output_file = DEFAULT_A_OUT_NAME;
//#endif
obstack_begin (&temporary_obstack, 0);
obstack_begin (&permanent_obstack, 0);
temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
current_demangling_style = auto_demangling;
p = getenv ("COLLECT_GCC_OPTIONS");
while (p && *p)//NULL
{
const char *q = extract_string (&p);
if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
num_c_args++;
}
obstack_free (&temporary_obstack, temporary_firstobj);
/* -fno-exceptions -w */
num_c_args += 2;
c_ptr = (const char **)
(c_argv = (char **) xcalloc (sizeof (char *), num_c_args));
if (argc < 2)
fatal ("no arguments");
值得注意的是-debug参数分析,看看这个参数的作用
[root@mail ~/gcc-3.0/build/gcc]# /usr/lib/gcc-lib/i386-redhat-linux/3.2.2/collect2
--eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc-
lib/i386-redhat-linux/3.2.2/../../../crt1.o /usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/../../../crti.o /usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtbegin.o -
L/usr/lib/gcc-lib/i386-redhat-linux/3.2.2 -L/usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/../../.. 1.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh /usr/lib/gcc-lib/i386-
redhat-linux/3.2.2/crtend.o /usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/../../../crtn.o -debug
Convert string
'/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/
bin' into prefixes, separator = ':'
- add prefix: /usr/local/sbin/
- add prefix: /usr/local/bin/
- add prefix: /sbin/
- add prefix: /bin/
- add prefix: /usr/sbin/
- add prefix: /usr/bin/
- add prefix: /usr/X11R6/bin/
- add prefix: /root/bin/
Looking for 'real-ld'
- failed: no entries in prefix list
Looking for 'collect-ld'
- failed: no entries in prefix list
Looking for 'ld'
- failed: no entries in prefix list
Looking for 'ld'
Looking for 'gnm'
- failed: no entries in prefix list
Looking for 'gnm'
Looking for 'nm'
- failed: no entries in prefix list
Looking for 'nm'
Looking for 'gstrip'
- failed: no entries in prefix list
Looking for 'gstrip'
Looking for 'strip'
- failed: no entries in prefix list
Looking for 'strip'
Looking for 'gcc'
- failed: no entries in prefix list
Looking for 'gcc'
collect2 version 3.2.2 20030222 (Red Hat Linux 3.2.2-5) (i386 Linux/ELF)
ld_file_name = /usr/bin/ld
c_file_name = /usr/bin/gcc
nm_file_name = /usr/bin/nm
strip_file_name = /usr/bin/strip
c_file = /tmp/ccCKYu7P.c
o_file = /tmp/ccKkwE4v.o
/usr/bin/ld --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o /usr/lib/gcc-lib/i386-
redhat-linux/3.2.2/../../../crti.o /usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/crtbegin.o -L/usr/lib/gcc-lib/i386-redhat-linux/3.2.2 -L/usr/lib/gcc-
lib/i386-redhat-linux/3.2.2/../../.. 1.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtend.o /usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/../../../crtn.o
[Leaving /tmp/ccCKYu7P.c]
[Leaving /tmp/ccKkwE4v.o]
[root@mail ~/gcc-3.0/build/gcc]#
输出了很多有用的信息
5.prefix
#ifdef SIGQUIT
if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
signal (SIGQUIT, handler);
#endif
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
signal (SIGINT, handler);
#ifdef SIGALRM
if (signal (SIGALRM, SIG_IGN) != SIG_IGN)
signal (SIGALRM, handler);
#endif
#ifdef SIGHUP
if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
signal (SIGHUP, handler);
#endif
if (signal (SIGSEGV, SIG_IGN) != SIG_IGN)
signal (SIGSEGV, handler);
#ifdef SIGBUS
if (signal (SIGBUS, SIG_IGN) != SIG_IGN)
signal (SIGBUS, handler);
#endif
/* Extract COMPILER_PATH and PATH into our prefix list. */
prefix_from_env ("COMPILER_PATH", &cpath);//NULL
/*对照-debug,看出进行如下的处理
Convert string
'/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/
bin' into prefixes, separator = ':'
- add prefix: /usr/local/sbin/
- add prefix: /usr/local/bin/
- add prefix: /sbin/
- add prefix: /bin/
- add prefix: /usr/sbin/
- add prefix: /usr/bin/
- add prefix: /usr/X11R6/bin/
- add prefix: /root/bin/
*/
prefix_from_env ("PATH", &path);
path的数据类型
/* Structure to hold all the directories in which to search for files to
execute. */
struct prefix_list
{
const char *prefix; /* String to prepend to the path. */
struct prefix_list *next; /* Next in linked list. */
};
struct path_prefix
{
struct prefix_list *plist; /* List of prefixes to try */
int max_len; /* Max length of a prefix in PLIST */
const char *name; /* Name of this list (used in config stuff) */
};
5.prefix_from_env
/* Take the value of the environment variable ENV, break it into a path, and
add of the entries to PPREFIX. */
static void
prefix_from_env (env, pprefix)
const char *env;
struct path_prefix *pprefix;
{
const char *p;
GET_ENV_PATH_LIST (p, env);//取得PATH环境变量的值
if (p)
prefix_from_string (p, pprefix);//分析PATH
}
#define GET_ENV_PATH_LIST(VAR,NAME) do { (VAR) = getenv (NAME); } while (0)
6.prefix_from_string
static void
prefix_from_string (p, pprefix)
const char *p;
struct path_prefix *pprefix;
{
const char *startp, *endp;
char *nstore = (char *) xmalloc (strlen (p) + 3);
/*
Convert string
'/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/
bin' into prefixes, separator = ':'
- add prefix: /usr/local/sbin/
- add prefix: /usr/local/bin/
- add prefix: /sbin/
- add prefix: /bin/
- add prefix: /usr/sbin/
- add prefix: /usr/bin/
- add prefix: /usr/X11R6/bin/
- add prefix: /root/bin/
*/
if (debug)
fprintf (stderr, "Convert string '%s' into prefixes, separator = '%c'\n", p,
PATH_SEPARATOR);
startp = endp = p;
while (1)
{
if (*endp == PATH_SEPARATOR || *endp == 0)//寻找':',\0
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)//空
{
strcpy (nstore, "./");
}
else if (! IS_DIR_SEPARATOR (endp[-1]))//不是/结尾
{
nstore[endp-startp] = DIR_SEPARATOR;//加上/
nstore[endp-startp+1] = 0;
}
else
nstore[endp-startp] = 0;
if (debug)
fprintf (stderr, " - add prefix: %s\n", nstore);
add_prefix (pprefix, nstore);
if (*endp == 0)
break;
endp = startp = endp + 1;
}
else
endp++;//下一个字符
}
}
7.add_prefix
/* Add an entry for PREFIX to prefix list PPREFIX. */
static void
add_prefix (pprefix, prefix)
struct path_prefix *pprefix;
const char *prefix;
{
struct prefix_list *pl, **prev;
int len;
if (pprefix->plist)
{
for (pl = pprefix->plist; pl->next; pl = pl->next)
;//找到最后一个元素
prev = &pl->next;
}
else
prev = &pprefix->plist;
/* Keep track of the longest prefix跟踪最长前缀 */
len = strlen (prefix);
if (len > pprefix->max_len)
pprefix->max_len = len;
pl = (struct prefix_list *) xmalloc (sizeof (struct prefix_list));
pl->prefix = xstrdup (prefix);
if (*prev)
pl->next = *prev;
else
pl->next = (struct prefix_list *) 0;
*prev = pl;//链入
}
8.查找需要的程序路径
/*
#ifdef CROSS_COMPILE
/* If we look for a program in the compiler directories, we just use
the short name, since these directories are already system-specific.
But it we look for a program in the system directories, we need to
qualify the program name with the target machine. * /
full_ld_suffix = concat(target_machine, "-", ld_suffix, NULL);
#if 0
full_gld_suffix = concat (target_machine, "-", gld_suffix, NULL);
#endif
full_nm_suffix = concat (target_machine, "-", nm_suffix, NULL);
full_gnm_suffix = concat (target_machine, "-", gnm_suffix, NULL);
#ifdef LDD_SUFFIX
full_ldd_suffix = concat (target_machine, "-", ldd_suffix, NULL);
#endif
full_strip_suffix = concat (target_machine, "-", strip_suffix, NULL);
full_gstrip_suffix = concat (target_machine, "-", gstrip_suffix, NULL);
#endif /* CROSS_COMPILE * /
*/
/* Try to discover a valid linker/nm/strip to use. */
/* Maybe we know the right file to use (if not cross). */
ld_file_name = 0;
/*
#ifdef DEFAULT_LINKER
if (access (DEFAULT_LINKER, X_OK) == 0)
ld_file_name = DEFAULT_LINKER;
if (ld_file_name == 0)
#endif
#ifdef REAL_LD_FILE_NAME
ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME);
if (ld_file_name == 0)
#endif
*/
/* Search the (target-specific) compiler dirs for ld'. */
ld_file_name = find_a_file (&cpath, real_ld_suffix);
/* Likewise for `collect-ld'. */
if (ld_file_name == 0)
ld_file_name = find_a_file (&cpath, collect_ld_suffix);
/* Search the compiler directories for `ld'. We have protection against
recursive calls in find_a_file. */
if (ld_file_name == 0)
ld_file_name = find_a_file (&cpath, ld_suffix);
/* Search the ordinary system bin directories
for `ld' (if native linking) or `TARGET-ld' (if cross). */
if (ld_file_name == 0)
ld_file_name = find_a_file (&path, full_ld_suffix);
//#ifdef REAL_NM_FILE_NAME
// nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME);
// if (nm_file_name == 0)
//#endif
nm_file_name = find_a_file (&cpath, gnm_suffix);
if (nm_file_name == 0)
nm_file_name = find_a_file (&path, full_gnm_suffix);
if (nm_file_name == 0)
nm_file_name = find_a_file (&cpath, nm_suffix);
if (nm_file_name == 0)
nm_file_name = find_a_file (&path, full_nm_suffix);
//#ifdef LDD_SUFFIX
// ldd_file_name = find_a_file (&cpath, ldd_suffix);
// if (ldd_file_name == 0)
// ldd_file_name = find_a_file (&path, full_ldd_suffix);
//#endif
//#ifdef REAL_STRIP_FILE_NAME
// strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME);
// if (strip_file_name == 0)
//#endif
strip_file_name = find_a_file (&cpath, gstrip_suffix);
if (strip_file_name == 0)
strip_file_name = find_a_file (&path, full_gstrip_suffix);
if (strip_file_name == 0)
strip_file_name = find_a_file (&cpath, strip_suffix);
if (strip_file_name == 0)
strip_file_name = find_a_file (&path, full_strip_suffix);
/* Determine the full path name of the C compiler to use. */
c_file_name = getenv ("COLLECT_GCC");//NULL
if (c_file_name == 0)
{
//#ifdef CROSS_COMPILE
// c_file_name = concat (target_machine, "-gcc", NULL);
//#else
c_file_name = "gcc";
//#endif
}
p = find_a_file (&cpath, c_file_name);
/* Here it should be safe to use the system search path since we should have
already qualified the name of the compiler when it is needed. */
if (p == 0)
p = find_a_file (&path, c_file_name);
if (p)
c_file_name = p;
9.find_a_file
/* Search for NAME using prefix list PPREFIX. We only look for executable
files.
Return 0 if not found, otherwise return its name, allocated with malloc. */
static char *
find_a_file (pprefix, name)
struct path_prefix *pprefix;
const char *name;
{
char *temp;
struct prefix_list *pl;
int len = pprefix->max_len + strlen (name) + 1;
/*
Looking for 'real-ld'
- failed: no entries in prefix list
Looking for 'collect-ld'
- failed: no entries in prefix list
Looking for 'ld'
- failed: no entries in prefix list
Looking for 'ld'
Looking for 'gnm'
- failed: no entries in prefix list
Looking for 'gnm'
Looking for 'nm'
- failed: no entries in prefix list
Looking for 'nm'
Looking for 'gstrip'
- failed: no entries in prefix list
Looking for 'gstrip'
Looking for 'strip'
- failed: no entries in prefix list
Looking for 'strip'
Looking for 'gcc'
- failed: no entries in prefix list
Looking for 'gcc'
*/
if (debug)
fprintf (stderr, "Looking for '%s'\n", name);
//#ifdef EXECUTABLE_SUFFIX
// len += strlen (EXECUTABLE_SUFFIX);
//#endif
temp = xmalloc (len);
/* Determine the filename to execute (special case for absolute paths). */
if (*name == '/'
//#ifdef HAVE_DOS_BASED_FILE_SYSTEM
// || (*name && name[1] == ':')
//#endif
)
{
if (access (name, X_OK) == 0)
{
strcpy (temp, name);
if (debug)
fprintf (stderr, " - found: absolute path\n");
return temp;
}
//#ifdef EXECUTABLE_SUFFIX
/* Some systems have a suffix for executable files.
So try appending that. */
// strcpy (temp, name);
// strcat (temp, EXECUTABLE_SUFFIX);
// if (access (temp, X_OK) == 0)
// return temp;
//#endif
if (debug)
fprintf (stderr, " - failed to locate using absolute path\n");
}
else
for (pl = pprefix->plist; pl; pl = pl->next)
{
struct stat st;
strcpy (temp, pl->prefix);
strcat (temp, name);
if (stat (temp, &st) >= 0
&& ! S_ISDIR (st.st_mode)
&& access (temp, X_OK) == 0)//找到
return temp;
//#ifdef EXECUTABLE_SUFFIX
/* Some systems have a suffix for executable files.
So try appending that. */
// strcat (temp, EXECUTABLE_SUFFIX);
// if (stat (temp, &st) >= 0
// && ! S_ISDIR (st.st_mode)
// && access (temp, X_OK) == 0)
// return temp;
//#endif
}
if (debug && pprefix->plist == NULL)
fprintf (stderr, " - failed: no entries in prefix list\n");
free (temp);
return 0;
}
10.生成临时文件
*ld1++ = *ld2++ = ld_file_name;// 第一个参数 /usr/bin/ld
/* Make temp file names. */
c_file = make_temp_file (".c");
o_file = make_temp_file (".o");
//#ifdef COLLECT_EXPORT_LIST
// export_file = make_temp_file (".x");
//#endif
ldout = make_temp_file (".ld");
*c_ptr++ = c_file_name;
*c_ptr++ = "-x";
*c_ptr++ = "c";
*c_ptr++ = "-c";
*c_ptr++ = "-o";
*c_ptr++ = o_file;
//#ifdef COLLECT_EXPORT_LIST
/* Generate a list of directories from LIBPATH. */
// prefix_from_env ("LIBPATH", &libpath_lib_dirs);
/* Add to this list also two standard directories where
AIX loader always searches for libraries. */
// add_prefix (&libpath_lib_dirs, "/lib");
// add_prefix (&libpath_lib_dirs, "/usr/lib");
//#endif
/* Get any options that the upper GCC wants to pass to the sub-GCC.
AIX support needs to know if -shared has been specified before
parsing commandline arguments. */
p = getenv ("COLLECT_GCC_OPTIONS");//NULL
while (p && *p)
{
const char *q = extract_string (&p);
if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
*c_ptr++ = obstack_copy0 (&permanent_obstack, q, strlen (q));
if (strcmp (q, "-EL") == 0 || strcmp (q, "-EB") == 0)
*c_ptr++ = obstack_copy0 (&permanent_obstack, q, strlen (q));
if (strncmp (q, "-shared", sizeof ("-shared") - 1) == 0)
shared_obj = 1;
if (*q == '-' && q[1] == 'B')
{
*c_ptr++ = obstack_copy0 (&permanent_obstack, q, strlen (q));
if (q[2] == 0)
{
q = extract_string (&p);
*c_ptr++ = obstack_copy0 (&permanent_obstack, q, strlen (q));
}
}
}
obstack_free (&temporary_obstack, temporary_firstobj);
*c_ptr++ = "-fno-exceptions";
*c_ptr++ = "-w";
11.make_temp_file
main->make_temp_file
/* Return a temporary file name (as a string) or NULL if unable to create
one. */
char *
make_temp_file (suffix)
const char *suffix;
{
const char *base = 0;
char *temp_filename;
int base_len, suffix_len;
int fd;
static char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 };// /tmp
static char usrtmp[] = { DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm',
'p', 0 };// /usr/tmp
base = try (getenv ("TMPDIR"), base);//NULL
base = try (getenv ("TMP"), base);//NULL
base = try (getenv ("TEMP"), base);//NULL
#ifdef P_tmpdir
base = try (P_tmpdir, base);
#endif
/* Try /usr/tmp, then /tmp. */
base = try (usrtmp, base);
base = try (tmp, base);
/* If all else fails, use the current directory! */
if (base == 0)
base = ".";
base_len = strlen (base);
if (suffix)
suffix_len = strlen (suffix);
else
suffix_len = 0;
//c_file = /tmp/ccY7hIYh.c
//o_file = /tmp/cc6x71Mp.o
temp_filename = xmalloc (base_len + 1 /*DIR_SEPARATOR*/
+ strlen (TEMP_FILE)
+ suffix_len + 1);
strcpy (temp_filename, base);
if (base_len != 0
&& temp_filename[base_len-1] != '/'
&& temp_filename[base_len-1] != DIR_SEPARATOR)
temp_filename[base_len++] = DIR_SEPARATOR;
strcpy (temp_filename + base_len, TEMP_FILE);
if (suffix)
strcat (temp_filename, suffix);
fd = mkstemps (temp_filename, suffix_len);
/* If mkstemps failed, then something bad is happening. Maybe we should
issue a message about a possible security attack in progress? */
if (fd == -1)
abort ();
/* Similarly if we can not close the file. */
if (close (fd))
abort ();
return temp_filename;
}
12. try
main->make_temp_file->try
static const char *
try (dir, base)
const char *dir, *base;
{
if (base != 0)//已经有了
return base;
if (dir != 0
&& access (dir, R_OK | W_OK | X_OK) == 0)
return dir;
return 0;
}
13.mkstemps
main->make_temp_file->mkstemps
/* Generate a unique temporary file name from TEMPLATE.
TEMPLATE has the form:
/ccXXXXXX
SUFFIX_LEN tells us how long is (it can be zero length).
The last six characters of TEMPLATE before must be "XXXXXX";
they are replaced with a string that makes the filename unique.
Returns a file descriptor open on the file for reading and writing. */
int
mkstemps (template, suffix_len)
char *template;
int suffix_len;
{
static const char letters[]
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static gcc_uint64_t value;
#ifdef HAVE_GETTIMEOFDAY
struct timeval tv;
#endif
char *XXXXXX;
size_t len;
int count;
len = strlen (template);
if ((int) len < 6 + suffix_len
|| strncmp (&template[len - 6 - suffix_len], "XXXXXX", 6))
{
return -1;//模板有问题
}
XXXXXX = &template[len - 6 - suffix_len];
#ifdef HAVE_GETTIMEOFDAY
/* Get some more or less random data. */
gettimeofday (&tv, NULL);
value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
#else
value += getpid ();
#endif
for (count = 0; count < TMP_MAX; ++count)
{
gcc_uint64_t v = value;
int fd;
/* Fill in the random bits. */
XXXXXX[0] = letters[v % 62];
v /= 62;
XXXXXX[1] = letters[v % 62];
v /= 62;
XXXXXX[2] = letters[v % 62];
v /= 62;
XXXXXX[3] = letters[v % 62];
v /= 62;
XXXXXX[4] = letters[v % 62];
v /= 62;
XXXXXX[5] = letters[v % 62];
fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600);//文件是否存在
if (fd >= 0)
/* The file does not exist. */
return fd;
/* This is a random value. It is only necessary that the next
TMP_MAX values generated by adding 7777 to VALUE are different
with (module 2^32). */
value += 7777;
}
/* We return the null string if we can't find a unique file name. */
template[0] = '\0';
return -1;
}
14.分析参数,构造ld1,ld2和object
/* !!! 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. */
first_file = 1;//<<<<
/*
(gdb) p *argv@10
$4 = {0xbffffa12 "/usr/local/bin/collect2", 0xbffffa2a "--eh-frame-hdr", 0xbffffa39
"-m",
0xbffffa3c "elf_i386", 0xbffffa45 "-dynamic-linker", 0xbffffa55 "/lib/ld-
linux.so.2",
0xbffffa68 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o",
0xbffffaa1 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crti.o",
0xbffffada "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtbegin.o",
0xbffffb0e "-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.2"}
*/
while ((arg = *++argv) != (char *) 0)//跳过第一个/usr/local/bin/collect2
{
*ld1++ = *ld2++ = arg;//复制参数
if (arg[0] == '-')
{
switch (arg[1])
{
//#ifdef COLLECT_EXPORT_LIST
/* We want to disable automatic exports on AIX when user
explicitly puts an export list in command line */
// case 'b':
// if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0)
// export_flag = 1;
// else if (arg[2] == '6' && arg[3] == '4')
// aix64_flag = 1;
// break;
///#endif
case 'd':
if (!strcmp (arg, "-debug"))
{
/* Already parsed. */
ld1--;
ld2--;
}
break;
case 'l':// -l
if (first_file)
{
/* place o_file BEFORE this argument! */
first_file = 0;
ld2--;
*ld2++ = o_file;//将o_file = /tmp/ccKkwE4v.o放在-l之
前
*ld2++ = arg;
}
//#ifdef COLLECT_EXPORT_LIST
// {
/* Resolving full library name. */
// const char *s = resolve_lib_name (arg+2);
/* Saving a full library name. */
// add_to_list (&libs, s);
// }
//#endif
break;
//#ifdef COLLECT_EXPORT_LIST
/* Saving directories where to search for libraries. */
// case 'L':
// add_prefix (&cmdline_lib_dirs, arg+2);
// break;
//#else
//#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES
// case 'L':
// if (is_in_args (arg, (const char **) ld1_argv, ld1-1))
// --ld1;
// break;
//#endif /* LINK_ELIMINATE_DUPLICATE_LDIRECTORIES */
//#endif
case 'o':// -o 记录output_file
if (arg[2] == '\0')
output_file = *ld1++ = *ld2++ = *++argv;//-o 1.o
else if (1
//#ifdef SWITCHES_NEED_SPACES
// && ! strchr (SWITCHES_NEED_SPACES, arg[1])
//#endif
)
output_file = &arg[2];//-o1.o
break;
case 'r':
if (arg[2] == '\0')
rflag = 1;
break;
case 's':
if (arg[2] == '\0' && do_collecting)
{
/* We must strip after the nm run, otherwise C++ linking
will not work. Thus we strip in the second ld run, or
else with strip if there is no second ld run. */
strip_flag = 1;
ld1--;
}
break;
case 'v':
if (arg[2] == '\0')
vflag = 1;
break;
}
}
//不是-开头
else if ((p = strrchr (arg, '.')) != (char *) 0
&& (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0
|| strcmp (p, ".so") == 0 || strcmp (p, ".lo") == 0
|| strcmp (p, ".obj") == 0))
{
//arg已存入ld2
if (first_file)
{
first_file = 0;
if (p[1] == 'o')
*ld2++ = o_file;//将o_file放在第一个.o文件后,第一个.o文件是crt1.o
else
{
/* place o_file BEFORE this argument! */
ld2--;
*ld2++ = o_file;//不是o,则放在它之前
*ld2++ = arg;
}
}
if (p[1] == 'o' || p[1] == 'l')
*object++ = arg;//记录.o文件
//#ifdef COLLECT_EXPORT_LIST
/* libraries can be specified directly, i.e. without -l flag. */
// else
// {
/* Saving a full library name. */
// add_to_list (&libs, arg);
// }
//#endif
}
}
15.执行连接
/*
#ifdef COLLECT_EXPORT_LIST
/* This is added only for debugging purposes. * /
if (debug)
{
fprintf (stderr, "List of libraries:\n");
dump_list (stderr, "\t", libs.first);
}
/* The AIX linker will discard static constructors in object files if
nothing else in the file is referenced, so look at them first. * /
{
const char **export_object_lst = (const char **)object_lst;
while (export_object_lst < object)
scan_prog_file (*export_object_lst++, PASS_OBJ);
}
{
struct id *list = libs.first;
for (; list; list = list->next)
scan_prog_file (list->name, PASS_FIRST);
}
if (exports.first)
{
char *buf = xmalloc (strlen (export_file) + 5);
sprintf (buf, "-bE:%s", export_file);
*ld1++ = buf;
*ld2++ = buf;
exportf = fopen (export_file, "w");
if (exportf == (FILE *) 0)
fatal_perror ("fopen %s", export_file);
write_aix_file (exportf, exports.first);
if (fclose (exportf))
fatal_perror ("fclose %s", export_file);
}
#endif
*/
*c_ptr++ = c_file;
*c_ptr = *ld1 = *object = (char *) 0;
if (vflag)
{
notice ("collect2 version %s", version_string);
#ifdef TARGET_VERSION
TARGET_VERSION;
#endif
fprintf (stderr, "\n");//collect2 version 3.2.2 20030222 (Red Hat Linux
3.2.2-5) (i386 Linux/ELF)
}
if (debug)
{
/*
ld_file_name = /usr/bin/ld
c_file_name = /usr/bin/gcc
nm_file_name = /usr/bin/nm
strip_file_name = /usr/bin/strip
c_file = /tmp/cc9B4EMF.c
o_file = /tmp/ccIomPob.o
*/
const char *ptr;
fprintf (stderr, "ld_file_name = %s\n",
(ld_file_name ? ld_file_name : "not found"));
fprintf (stderr, "c_file_name = %s\n",
(c_file_name ? c_file_name : "not found"));
fprintf (stderr, "nm_file_name = %s\n",
(nm_file_name ? nm_file_name : "not found"));
//#ifdef LDD_SUFFIX
// fprintf (stderr, "ldd_file_name = %s\n",
// (ldd_file_name ? ldd_file_name : "not found"));
//#endif
fprintf (stderr, "strip_file_name = %s\n",
(strip_file_name ? strip_file_name : "not found"));
fprintf (stderr, "c_file = %s\n",
(c_file ? c_file : "not found"));
fprintf (stderr, "o_file = %s\n",
(o_file ? o_file : "not found"));
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_ENV);
if (ptr)
fprintf (stderr, "%-20s= %s\n", LIBRARY_PATH_ENV, ptr);
fprintf (stderr, "\n");
}
/* Load the program, searching all libraries and attempting to provide
undefined symbols from repository information. */
/* On AIX we do this later. */
//#ifndef COLLECT_EXPORT_LIST
/*
//传给ld的参数
(gdb) p *ld1_argv@20
$20 = {0x80637f8 "/usr/bin/ld", 0xbffffa2a "--eh-frame-hdr", 0xbffffa39 "-m",
0xbffffa3c "elf_i386",
0xbffffa45 "-dynamic-linker", 0xbffffa55 "/lib/ld-linux.so.2",
0xbffffa68 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o",
0xbffffaa1 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crti.o",
0xbffffada "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtbegin.o",
0xbffffb0e "-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.2",
0xbffffb39 "-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../..", 0xbffffb6d
"1.o", 0xbffffb71 "-lgcc",
0xbffffb77 "-lgcc_eh", 0xbffffb80 "-lc", 0xbffffb84 "-lgcc", 0xbffffb8a "-
lgcc_eh",
0xbffffb93 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtend.o",
0xbffffbc5 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crtn.o", 0x0}
(gdb)
(gdb) p *ld2_argv@30
$27 = {0x80637f8 "/usr/bin/ld", 0xbffffa2a "--eh-frame-hdr", 0xbffffa39 "-m",
0xbffffa3c "elf_i386",
0xbffffa45 "-dynamic-linker", 0xbffffa55 "/lib/ld-linux.so.2",
0xbffffa68 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o", 0x8063878
"/tmp/ccakLwZh.o", ///<<<<<注意这里,插入了特别的目标文件
0xbffffaa1 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crti.o",
0xbffffada "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtbegin.o",
0xbffffb0e "-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.2",
0xbffffb39 "-L/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../..", 0xbffffb6d
"1.o", 0xbffffb71 "-lgcc",
0xbffffb77 "-lgcc_eh", 0xbffffb80 "-lc", 0xbffffb84 "-lgcc", 0xbffffb8a "-
lgcc_eh",
0xbffffb93 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtend.o",
0xbffffbc5 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crtn.o", 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x51 }
(gdb) p *object_lst@15
$15 = {0xbffffa68 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o",
0xbffffaa1 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crti.o",
0xbffffada "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtbegin.o", 0xbffffb6d
"1.o",
0xbffffb93 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtend.o",
0xbffffbc5 "/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crtn.o", 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0}
(gdb) p *c_argv@30
$26 = {0x8063848 "/usr/bin/gcc", 0x805c572 "-x", 0x805c575 "c", 0x805c577 "-c",
0x805c57a "-o",
0x8063878 "/tmp/ccakLwZh.o", 0x805c58d "-fno-exceptions", 0x805c59d "-w",
0x8063860 "/tmp/ccEJQY4I.c",
0x0 }
*/
do_tlink (ld1_argv, object_lst);
16.do_tlink
/* Entry point for tlink. Called from main in collect2.c.
Iteratively try to provide definitions for all the unresolved symbols
mentioned in the linker error messages.
LD_ARGV is an array of arguments for the linker.
OBJECT_LST is an array of object files that we may be able to recompile
to provide missing definitions. Currently ignored. */
void
do_tlink (ld_argv, object_lst)
char **ld_argv, **object_lst ATTRIBUTE_UNUSED;
{
int exit = tlink_execute ("ld", ld_argv, ldout);//ldout="/tmp/ccpp6cXv.ld"
17.tlink_execute
main->do_tlink->tlink_execute
static int
tlink_execute (prog, argv, redir)
const char *prog;
char **argv;
const char *redir;
{
collect_execute (prog, argv, redir);
return collect_wait (prog);
}
18.collect_execute
main->do_tlink->tlink_execute->collect_execute
/* Execute a program, and wait for the reply. */
void
collect_execute (prog, argv, redir)
const char *prog;
char **argv;
const char *redir;
{
char *errmsg_fmt;
char *errmsg_arg;
int redir_handle = -1;
int stdout_save = -1;
int stderr_save = -1;
if (vflag || debug)
{
char **p_argv;
const char *str;
if (argv[0])
fprintf (stderr, "%s", argv[0]);
else
notice ("[cannot find %s]", prog);
///usr/bin/ld --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o /usr/lib/gcc-lib/i386-
redhat-linux/3.2.2/../../../crti.o /usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/crtbegin.o -L/usr/lib/gcc-lib/i386-redhat-linux/3.2.2 -L/usr/lib/gcc-
lib/i386-redhat-linux/3.2.2/../../.. 1.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtend.o /usr/lib/gcc-lib/i386-redhat-
linux/3.2.2/../../../crtn.o
for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++)
fprintf (stderr, " %s", str);
fprintf (stderr, "\n");
}
fflush (stdout);
fflush (stderr);
/* If we cannot find a program we need, complain error. Do this here
since we might not end up needing something that we could not find. */
if (argv[0] == 0)
fatal ("cannot find `%s'", prog);
if (redir)//输出全部重定向到ldout
{
/* Open response file. */
redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT);///tmp/ccpp6cXv.ld
/* Duplicate the stdout and stderr file handles
so they can be restored later. */
stdout_save = dup (STDOUT_FILENO);
if (stdout_save == -1)
fatal_perror ("redirecting stdout: %s", redir);
stderr_save = dup (STDERR_FILENO);
if (stderr_save == -1)
fatal_perror ("redirecting stdout: %s", redir);
/* Redirect stdout & stderr to our response file. */
dup2 (redir_handle, STDOUT_FILENO);
dup2 (redir_handle, STDERR_FILENO);
}
pexecute_pid = pexecute (argv[0], argv, argv[0], NULL,
&errmsg_fmt, &errmsg_arg,
(PEXECUTE_FIRST | PEXECUTE_LAST | PEXECUTE_SEARCH));
if (redir)
{
/* Restore stdout and stderr to their previous settings. */
dup2 (stdout_save, STDOUT_FILENO);
dup2 (stderr_save, STDERR_FILENO);
/* Close reponse file. */
close (redir_handle);
}
if (pexecute_pid == -1)
fatal_perror (errmsg_fmt, errmsg_arg);
}
19.返回到do_tlink
main->do_tlink
tlink_init ();
if (exit)//如果出错
{
int i = 0;
/* Until collect does a better job of figuring out which are object
files, assume that everything on the command line could be. */
if (read_repo_files (ld_argv))
20.read_repo_files 读取rpo文件并进行处理
main->do_tlink->read_repo_files
/* The first phase of processing: determine which object files have
.rpo files associated with them, and read in the information. */
static int
read_repo_files (object_lst)
char **object_lst;
{
char **object = object_lst;
for (; *object; object++)
{
const char *p;
file *f;
/* Don't bother trying for ld flags. */
if (*object[0] == '-')
continue;
p = frob_extension (*object, ".rpo");
/*
/usr/bin/ld.rpo
elf_i386.rpo
/lib/ld-linux.so.rpo
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.rpo
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crti.rpo
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtbegin.rpo
1.rpo
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/crtend.rpo
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crtn.rpo
*/
if (! file_exists (p))
continue;
f = file_hash_lookup (p);
read_repo_file (f);
}
if (file_stack != NULL && ! recompile_files ())
return 0;
return (symbol_stack != NULL);
}
不清楚rpo的作用,我们的例子也没有rpo文件,因此返回0
21.返回到do_tlink
main->do_tlink
while (exit && i++ < MAX_ITERATIONS)
{
if (tlink_verbose >= 3)
dump_file (ldout);
demangle_new_symbols ();
if (! scan_linker_output (ldout))
break;
if (! recompile_files ())
break;
if (tlink_verbose)
fprintf (stderr, _("collect: relinking\n"));
exit = tlink_execute ("ld", ld_argv, ldout);
}
}
dump_file (ldout);//显示ld输出
unlink (ldout);//删除ldout
if (exit)//打印错误信息
{
error ("ld returned %d exit status", exit);
collect_exit (exit);//exit
}
}
22.dump_file
main->do_tlink->dump_file
void
dump_file (name)
const char *name;
{
FILE *stream = fopen (name, "r");
int no_demangle = !! getenv ("COLLECT_NO_DEMANGLE");//是否不进行名字demangle
if (stream == 0)
return;
while (1)
{
int c;
while (c = getc (stream),
c != EOF && (ISALNUM (c) || c == '_' || c == '$' || c == '.'))//查找
symbol
obstack_1grow (&temporary_obstack, c);//字符存入temporary_obstack
if (obstack_object_size (&temporary_obstack) > 0)
{
const char *word, *p;
char *result;
obstack_1grow (&temporary_obstack, '\0');
word = obstack_finish (&temporary_obstack);
if (*word == '.')
++word, putc ('.', stderr);
p = word;
if (*p == '_' && prepends_underscore)
++p;
if (no_demangle)
result = 0;
else
result = cplus_demangle (p, DMGL_PARAMS | DMGL_ANSI);//demangle
if (result)
{
int diff;
fputs (result, stderr);
diff = strlen (word) - strlen (result);
while (diff > 0)
--diff, putc (' ', stderr);
while (diff < 0 && c == ' ')
++diff, c = getc (stream);
free (result);
}
else
fputs (word, stderr);
fflush (stderr);
obstack_free (&temporary_obstack, temporary_firstobj);
}
if (c == EOF)
break;
putc (c, stderr);//其它字符
}
fclose (stream);
}
如何不进行名字demangle,dump_file的功能就是直接输出ldout.如果要进行名字demangle,特别
是c++程序,则进行而外的处理,将mangle后的名字进行demangle,便于程序员阅读。
例如
[root@mail ~]# cat 1.cpp
#include
using namespace std ;
class A {
public:
A() {
}
} ;
void
f( void )
{
throw A( ) ;
}
int
main( int argc, char *argv[] )
{
try {
f( ) ;
}
catch( A &e ) {
cout << "Exception occured!" << endl ;
}
return 0 ;
}
[root@mail ~]# gcc 1.cpp
/tmp/ccKQmW1O.o: In function `f()':
1.cpp:(.text+0x1c): undefined reference to `__cxa_allocate_exception'
1.cpp:(.text+0x41): undefined reference to `__cxa_throw'
/tmp/ccKQmW1O.o: In function `main':
1.cpp:(.text+0x78): undefined reference to `__cxa_begin_catch'
1.cpp:(.text+0x86): undefined reference to `std::basic_ostream
std::char_traits >& std::endl >
(std::basic_ostream >&)'
1.cpp:(.text+0x93): undefined reference to `std::cout'
1.cpp:(.text+0x98): undefined reference to `std::basic_ostream
std::char_traits >& std::operator<< >
(std::basic_ostream >&, char const*)'
1.cpp:(.text+0xa1): undefined reference to `std::basic_ostream
std::char_traits >::operator<<(std::basic_ostream
std::char_traits >& (*)(std::basic_ostream >&))'
1.cpp:(.text+0xb1): undefined reference to `__cxa_end_catch'
1.cpp:(.text+0xc4): undefined reference to `__cxa_end_catch'
/tmp/ccKQmW1O.o: In function `__static_initialization_and_destruction_0(int, int)':
1.cpp:(.text+0xf0): undefined reference to `std::ios_base::Init::Init[in-charge]()'
/tmp/ccKQmW1O.o: In function `__tcf_0':
1.cpp:(.text+0x11f): undefined reference to `std::ios_base::Init::~Init [in-
charge]()'
/tmp/ccKQmW1O.o:(.gnu.linkonce.d._ZTI1A+0x0): undefined reference to `vtable for
__cxxabiv1::__class_type_info'
/tmp/ccKQmW1O.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
这里的std::basic_ostream >& std::endl
std::char_traits >(std::basic_ostream >&)等就是经
过demangle后的名字
我们看看不进行demangle是什么结果
[root@mail ~]# COLLECT_NO_DEMANGLE=1 gcc 1.cpp
/tmp/cc4UN7VE.o: In function `_Z1fv':
1.cpp:(.text+0x1c): undefined reference to `__cxa_allocate_exception'
1.cpp:(.text+0x41): undefined reference to `__cxa_throw'
/tmp/cc4UN7VE.o: In function `main':
1.cpp:(.text+0x78): undefined reference to `__cxa_begin_catch'
1.cpp:(.text+0x86): undefined reference to
`_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_'
1.cpp:(.text+0x93): undefined reference to `_ZSt4cout'
1.cpp:(.text+0x98): undefined reference to
`_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc'
1.cpp:(.text+0xa1): undefined reference to `_ZNSolsEPFRSoS_E'
1.cpp:(.text+0xb1): undefined reference to `__cxa_end_catch'
1.cpp:(.text+0xc4): undefined reference to `__cxa_end_catch'
/tmp/cc4UN7VE.o: In function `_Z41__static_initialization_and_destruction_0ii':
1.cpp:(.text+0xf0): undefined reference to `_ZNSt8ios_base4InitC1Ev'
/tmp/cc4UN7VE.o: In function `__tcf_0':
1.cpp:(.text+0x11f): undefined reference to `_ZNSt8ios_base4InitD1Ev'
/tmp/cc4UN7VE.o:(.gnu.linkonce.d._ZTI1A+0x0): undefined reference to
`_ZTVN10__cxxabiv117__class_type_infoE'
/tmp/cc4UN7VE.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
[root@mail ~]#
显然许多名字不知所云
23.返回到main
/* If -r or they will be run via some other method, do not build the
constructor or destructor list, just return now. */
if (rflag
//#ifndef COLLECT_EXPORT_LIST
|| ! do_collecting//<<<对于觉大多数配置,do_collecting都是0
//#endif
)
{
//#ifdef COLLECT_EXPORT_LIST
/* Do the link we avoided above if we are exiting. */
// do_tlink (ld1_argv, object_lst);
/* But make sure we delete the export file we may have created. */
// if (export_file != 0 && export_file[0])
// maybe_unlink (export_file);
//#endif
maybe_unlink (c_file);
maybe_unlink (o_file);
return 0;
}
因此到这里collect2的工作就完成了.
24.maybe_unlink
/* Unlink a file unless we are debugging. */
static void
maybe_unlink (file)
const char *file;
{
if (!debug)
unlink (file);
else
notice ("[Leaving %s]\n", file);
}
可见处于调试模式下,不会删除这些临时文件,这样便于检查。
通过向gcc传-Wl,-debug参数就能控制collect2进入调试模式.
例如gcc 1.cpp -Wl,-debug
阅读(2745) | 评论(0) | 转发(0) |