+static int undef_count = 0;
+
+struct key_value
+{
+ char *key;
+ const char *oname;
+};
+
+static struct key_value *udef_table;
+
+static int undef_sort_cmp (const void *l1, const void *r1)
+{
+ const struct key_value *l = l1;
+ const struct key_value *r = r1;
+
+ return strcmp (l->key, r->key);
+}
+
+static struct bfd_link_hash_entry *
+pe_find_cdecl_alias_match (struct bfd_link_info *linfo, char *name)
+{
+ struct bfd_link_hash_entry *h = NULL;
+ struct key_value *kv;
+ struct key_value key;
+ char *at, *lname = (char *) alloca (strlen (name) + 3);
+
+ strcpy (lname, name);
+
+ at = strchr (lname + (lname[0] == '@'), '@');
+ if (at)
+ at[1] = 0;
+
+ key.key = lname;
+ kv = bsearch (&key, udef_table, undef_count, sizeof (struct key_value),
+ undef_sort_cmp);
+
+ if (kv)
+ {
+ h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+ if (h->type == bfd_link_hash_undefined)
+ return h;
+ }
+ if (lname[0] == '?')
+ return NULL;
+ if (at || lname[0] == '@')
+ {
+ if (lname[0] == '@')
+ {
+ if (pe_details->underscored)
+ lname[0] = '_';
+ else
+ strcpy (lname, lname + 1);
+ key.key = lname;
+ kv = bsearch (&key, udef_table, undef_count,
+ sizeof (struct key_value), undef_sort_cmp);
+ if (kv)
+ {
+ h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+ if (h->type == bfd_link_hash_undefined)
+ return h;
+ }
+ }
+ if (at)
+ *strchr (lname, '@') = 0;
+ key.key = lname;
+ kv = bsearch (&key, udef_table, undef_count,
+ sizeof (struct key_value), undef_sort_cmp);
+ if (kv)
+ {
+ h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+ if (h->type == bfd_link_hash_undefined)
+ return h;
+ }
+ return NULL;
+ }
+
+ strcat (lname, "@");
+ key.key = lname;
+ kv = bsearch (&key, udef_table, undef_count,
+ sizeof (struct key_value), undef_sort_cmp);
+
+ if (kv)
+ {
+ h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+ if (h->type == bfd_link_hash_undefined)
+ return h;
+ }
+
+ if (lname[0] == '_' && pe_details->underscored)
+ lname[0] = '@';
+ else
+ {
+ memmove (lname + 1, lname, strlen (lname) + 1);
+ lname[0] = '@';
+ }
+ key.key = lname;
+
+ kv = bsearch (&key, udef_table, undef_count,
+ sizeof (struct key_value), undef_sort_cmp);
+
+ if (kv)
+ {
+ h = bfd_link_hash_lookup (linfo->hash, kv->oname, FALSE, FALSE, FALSE);
+ if (h->type == bfd_link_hash_undefined)
+ return h;
+ }
+
+ return NULL;
+}
+
+static bfd_boolean
+pe_undef_count (struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED,
+ void *inf ATTRIBUTE_UNUSED)
+{
+ if (h->type == bfd_link_hash_undefined)
+ undef_count++;
+ return TRUE;
+}
+
+static bfd_boolean
+pe_undef_fill (struct bfd_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
+{
+ if (h->type == bfd_link_hash_undefined)
+ {
+ char *at;
+
+ udef_table[undef_count].key = xstrdup (h->root.string);
+ at = strchr (udef_table[undef_count].key
+ + (udef_table[undef_count].key[0] == '@'), '@');
+ if (at)
+ at[1] = 0;
+ udef_table[undef_count].oname = h->root.string;
+ undef_count++;
+ }
+ return TRUE;
+}
+