This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: Another linker performance issue
- From: John Reiser <jreiser at bitwagon dot com>
- To: binutils at sourceware dot org
- Date: Wed, 29 Feb 2012 08:42:37 -0800
- Subject: Re: Another linker performance issue
- References: <4F4E427E.7040603@obry.net>
> static bfd_boolean
> pe_undef_alias_cdecl_match (struct bfd_link_hash_entry *h, void *inf)
> {
> int sl;
> char *string = inf;
> const char *hs = h->root.string;
>
> sl = strlen (string);
> if (h->type == bfd_link_hash_undefined
> && ((*hs == '@' && (!pe_details->underscored || *string == '_')
> && strncmp (hs + 1, string + (pe_details->underscored != 0),
> sl - (pe_details->underscored != 0)) == 0)
> || strncmp (hs, string, sl) == 0)
> && h->root.string[sl] == '@')
> {
> found_sym = h;
> return FALSE;
> }
> return TRUE;
> }
>
> static struct bfd_link_hash_entry *
> pe_find_cdecl_alias_match (char *name)
> {
> found_sym = 0;
> bfd_link_hash_traverse (link_info.hash, pe_undef_alias_cdecl_match,
> (char *) name);
> return sym;
> }
> In fact we traverse the hash table, looking for all symbols for a
> matching alias! For big applications this is not a proper
> implementation.
Even if there is no progress in choosing a better global strategy
for finding alias matches, the programmer can help the compiler generate
better code. 20% better is only 20%, but that's one minute
in this case.
Make two parametric subroutines, one for (pe_details->underscored == 0)
and one for (pe_details->underscored != 0) . Check bfd_link_hash_undefined
before computing strlen(). Use the characteristic value of a comparison
operation to simplify code and avoid branching. Use 'const' as much as
possible.
[Does the original code have a bug when it checks
(h->root.string[sl] == '@') even if (*hs == '@') ?
The index [sl] looks suspicious in that case.]
-----
static bfd_boolean
pe_undef_alias_cdecl_match (struct bfd_link_hash_entry const *const h,
void const *const inf)
{
if (h->type == bfd_link_hash_undefined) {
char const *const hs = h->root.string;
char const *const string = inf;
int const sl = strlen (string);
if (0 == strncmp (hs + ('@' == hs[0]), string, sl)
&& hs[sl] == '@') {
found_sym = h;
return FALSE;
}
}
}
return TRUE;
}
/* Note trailing underscore in subroutine name below. */
static bfd_boolean
pe_undef_alias_cdecl_match_ (struct bfd_link_hash_entry const *const h,
void const *const inf)
{
if (h->type == bfd_link_hash_undefined) {
char const *const hs = h->root.string;
char const *const string = inf;
int const sl = strlen (string);
if ('_' == string[0]
&& 0 == strncmp (hs + ('@' == hs[0]), 1+ string, -1+ sl)
&& hs[sl] == '@') {
found_sym = h;
return FALSE;
}
}
}
return TRUE;
}
static struct bfd_link_hash_entry *
pe_find_cdecl_alias_match (char *name)
{
found_sym = 0;
if (pe_details->underscored)
bfd_link_hash_traverse (link_info.hash, pe_undef_alias_cdecl_match_,
(char *) name);
else
bfd_link_hash_traverse (link_info.hash, pe_undef_alias_cdecl_match,
(char *) name);
return sym;
}
-----
--