summaryrefslogtreecommitdiff
path: root/gcc/tlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tlink.c')
-rw-r--r--gcc/tlink.c98
1 files changed, 76 insertions, 22 deletions
diff --git a/gcc/tlink.c b/gcc/tlink.c
index f0540478e72..67c7086ceb1 100644
--- a/gcc/tlink.c
+++ b/gcc/tlink.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "collect2.h"
#include "filenames.h"
#include "diagnostic-core.h"
+#include "vec.h"
/* TARGET_64BIT may be defined to use driver specific functionality. */
#undef TARGET_64BIT
@@ -67,10 +68,14 @@ typedef struct file_hash_entry
int tweaking;
} file;
+typedef const char *str;
+DEF_VEC_P(str);
+DEF_VEC_ALLOC_P(str,heap);
+
typedef struct demangled_hash_entry
{
const char *key;
- const char *mangled;
+ VEC(str,heap) *mangled;
} demangled;
/* Hash and comparison functions for these hash tables. */
@@ -435,9 +440,15 @@ maybe_tweak (char *line, file *f)
sym->tweaked = 1;
if (line[0] == 'O')
- line[0] = 'C';
+ {
+ line[0] = 'C';
+ sym->chosen = 1;
+ }
else
- line[0] = 'O';
+ {
+ line[0] = 'O';
+ sym->chosen = 0;
+ }
}
}
@@ -598,8 +609,32 @@ demangle_new_symbols (void)
continue;
dem = demangled_hash_lookup (p, true);
- dem->mangled = sym->key;
+ VEC_safe_push (str, heap, dem->mangled, sym->key);
+ }
+}
+
+/* We want to tweak symbol SYM. Return true if all is well, false on
+ error. */
+
+static bool
+start_tweaking (symbol *sym)
+{
+ if (sym && sym->tweaked)
+ {
+ error ("'%s' was assigned to '%s', but was not defined "
+ "during recompilation, or vice versa",
+ sym->key, sym->file->key);
+ return 0;
+ }
+ if (sym && !sym->tweaking)
+ {
+ if (tlink_verbose >= 2)
+ fprintf (stderr, _("collect: tweaking %s in %s\n"),
+ sym->key, sym->file->key);
+ sym->tweaking = 1;
+ file_push (sym->file);
}
+ return true;
}
/* Step through the output of the linker, in the file named FNAME, and
@@ -616,8 +651,11 @@ scan_linker_output (const char *fname)
{
char *p = line, *q;
symbol *sym;
+ demangled *dem = 0;
int end;
int ok = 0;
+ unsigned ix;
+ str s;
/* On darwin9, we might have to skip " in " lines as well. */
if (skip_next_in_line
@@ -662,7 +700,6 @@ scan_linker_output (const char *fname)
/* Try a mangled name in quotes. */
{
char *oldq = q + 1;
- demangled *dem = 0;
q = 0;
/* On darwin9, we look for "foo" referenced from:\n\(.* in .*\n\)* */
@@ -718,9 +755,7 @@ scan_linker_output (const char *fname)
{
*q = 0;
dem = demangled_hash_lookup (p, false);
- if (dem)
- sym = symbol_hash_lookup (dem->mangled, false);
- else
+ if (!dem)
{
if (!strncmp (p, USER_LABEL_PREFIX,
strlen (USER_LABEL_PREFIX)))
@@ -730,24 +765,43 @@ scan_linker_output (const char *fname)
}
}
- if (sym && sym->tweaked)
+ if (dem)
{
- error ("'%s' was assigned to '%s', but was not defined "
- "during recompilation, or vice versa",
- sym->key, sym->file->key);
- fclose (stream);
- return 0;
- }
- if (sym && !sym->tweaking)
- {
- if (tlink_verbose >= 2)
- fprintf (stderr, _("collect: tweaking %s in %s\n"),
- sym->key, sym->file->key);
- sym->tweaking = 1;
- file_push (sym->file);
+ /* We found a demangled name. If this is the name of a
+ constructor or destructor, there can be several mangled names
+ that match it, so choose or unchoose all of them. If some are
+ chosen and some not, leave the later ones that don't match
+ alone for now; either this will cause the link to suceed, or
+ on the next attempt we will switch all of them the other way
+ and that will cause it to succeed. */
+ int chosen = 0;
+ int len = VEC_length (str, dem->mangled);
+ ok = true;
+ FOR_EACH_VEC_ELT (str, dem->mangled, ix, s)
+ {
+ sym = symbol_hash_lookup (s, false);
+ if (ix == 0)
+ chosen = sym->chosen;
+ else if (sym->chosen != chosen)
+ /* Mismatch. */
+ continue;
+ /* Avoid an error about re-tweaking when we guess wrong in
+ the case of mismatch. */
+ if (len > 1)
+ sym->tweaked = false;
+ ok = start_tweaking (sym);
+ }
}
+ else
+ ok = start_tweaking (sym);
obstack_free (&temporary_obstack, temporary_firstobj);
+
+ if (!ok)
+ {
+ fclose (stream);
+ return 0;
+ }
}
fclose (stream);