reloc_howto_type howto_table_ext[] =
{
- HOWTO(RELOC_8, 0, 0, 8, false, 0, true, true,0,"8", false, 0,0x000000ff, false),
- HOWTO(RELOC_16, 0, 1, 16, false, 0, true, true,0,"16", false, 0,0x0000ffff, false),
- HOWTO(RELOC_32, 0, 2, 32, false, 0, true, true,0,"32", false, 0,0xffffffff, false),
+/* type rightshift size bitsize pc_ bit absol compl spec name partial_ src_ dst_ pcrel_
+ rela pos ute ain_on ial_ inplace mask mask offset
+ tive _overf fn */
+ HOWTO(RELOC_8, 0, 0, 8, false, 0, true, true,0,"8", false, 0,0x000000ff, false),
+ HOWTO(RELOC_16, 0, 1, 16, false, 0, true, true,0,"16", false, 0,0x0000ffff, false),
+ HOWTO(RELOC_32, 0, 2, 32, false, 0, true, true,0,"32", false, 0,0xffffffff, false),
HOWTO(RELOC_DISP8, 0, 0, 8, true, 0, false, true,0,"DISP8", false, 0,0x000000ff, false),
HOWTO(RELOC_DISP16, 0, 1, 16, true, 0, false, true,0,"DISP16", false, 0,0x0000ffff, false),
HOWTO(RELOC_DISP32, 0, 2, 32, true, 0, false, true,0,"DISP32", false, 0,0xffffffff, false),
HOWTO(RELOC_WDISP30,2, 2, 30, true, 0, false, true,0,"WDISP30", false, 0,0x3fffffff, false),
HOWTO(RELOC_WDISP22,2, 2, 22, true, 0, false, true,0,"WDISP22", false, 0,0x003fffff, false),
HOWTO(RELOC_HI22, 10, 2, 22, false, 0, false, true,0,"HI22", false, 0,0x003fffff, false),
- HOWTO(RELOC_22, 0, 2, 22, false, 0, false, true,0,"22", false, 0,0x003fffff, false),
- HOWTO(RELOC_13, 0, 2, 13, false, 0, false, true,0,"13", false, 0,0x00001fff, false),
- HOWTO(RELOC_LO10, 0, 2, 10, false, 0, false, true,0,"LO10", false, 0,0x000003ff, false),
+ HOWTO(RELOC_22, 0, 2, 22, false, 0, false, true,0,"22", false, 0,0x003fffff, false),
+ HOWTO(RELOC_13, 0, 2, 13, false, 0, false, true,0,"13", false, 0,0x00001fff, false),
+ HOWTO(RELOC_LO10, 0, 2, 10, false, 0, false, true,0,"LO10", false, 0,0x000003ff, false),
HOWTO(RELOC_SFA_BASE,0, 2, 32, false, 0, false, true,0,"SFA_BASE", false, 0,0xffffffff, false),
HOWTO(RELOC_SFA_OFF13,0,2, 32, false, 0, false, true,0,"SFA_OFF13",false, 0,0xffffffff, false),
HOWTO(RELOC_BASE10, 0, 2, 16, false, 0, false, true,0,"BASE10", false, 0,0x0000ffff, false),
HOWTO(RELOC_SEGOFF16,0, 2, 0, false, 0, false, true,0,"SEGOFF16", false, 0,0x00000000, false),
HOWTO(RELOC_GLOB_DAT,0, 2, 0, false, 0, false, true,0,"GLOB_DAT", false, 0,0x00000000, false),
HOWTO(RELOC_JMP_SLOT,0, 2, 0, false, 0, false, true,0,"JMP_SLOT", false, 0,0x00000000, false),
- HOWTO(RELOC_RELATIVE,0, 2, 0, false, 0, false, true,0,"RELATIVE", false, 0,0x00000000, false),
+ HOWTO(RELOC_RELATIVE,0, 2, 0, false, 0, false, true,0,"RELATIVE", false, 0,0x00000000, false),
};
/* Convert standard reloc records to "arelent" format (incl byte swap). */
sym_pointer->e_type[0] &= ~N_TYPE;
- if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) {
- sym_pointer->e_type[0] |= N_BSS;
+ /* We attempt to order these tests by decreasing frequency of success,
+ according to tcov when linking the linker. */
+ if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) {
+ sym_pointer->e_type[0] |= N_ABS;
+ }
+ else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) {
+ sym_pointer->e_type[0] |= N_TEXT;
}
else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) {
sym_pointer->e_type[0] |= N_DATA;
}
- else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) {
- sym_pointer->e_type[0] |= N_TEXT;
+ else if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) {
+ sym_pointer->e_type[0] |= N_BSS;
}
- else if (bfd_get_output_section(cache_ptr) == &bfd_abs_section)
- {
- sym_pointer->e_type[0] |= N_ABS;
- }
else if (bfd_get_output_section(cache_ptr) == &bfd_und_section)
{
sym_pointer->e_type[0] = (N_UNDF | N_EXT);
(sym_pointer+1)->e_type[0] = 1;
}
- if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) {
- sym_pointer->e_type[0] |= N_EXT;
- }
if (cache_ptr->flags & BSF_DEBUGGING) {
sym_pointer->e_type[0] = ((aout_symbol_type *)cache_ptr)->type;
}
+ else if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) {
+ sym_pointer->e_type[0] |= N_EXT;
+ }
if (cache_ptr->flags & BSF_CONSTRUCTOR) {
int type = ((aout_symbol_type *)cache_ptr)->type;
switch (type)
struct stringtab_entry {
/* Hash value for this string. Only useful so long as we aren't doing
substring matches. */
- int hash;
+ unsigned int hash;
/* Next node to look at, depending on whether the hash value of the string
being searched for is less than or greater than the hash value of the
/* Some utility functions for the string table code. */
-static INLINE int
-hash (string)
- char *string;
+/* For speed, only hash on the first this many bytes of strings.
+ This number was chosen by profiling ld linking itself, with -g. */
+#define HASHMAXLEN 25
+
+#define HASH_CHAR(c) (sum ^= sum >> 20, sum ^= sum << 7, sum += (c))
+
+static INLINE unsigned int
+hash (string, len)
+ unsigned char *string;
+ register unsigned int len;
{
- unsigned int sum = 0;
- while (*string)
+ register unsigned int sum = 0;
+
+ if (len > HASHMAXLEN)
{
-#if 0
- /* This expression borrowed from some code in gnu make. */
- sum += *string++, sum = (sum << 7) + (sum >> 20);
-#endif
- /* This appears to get a better distribution, at least for my one
- test case. Do some analysis on this later, get a real hash
- algorithm. */
- sum ^= sum >> 20;
- sum ^= sum << 7;
- sum += *string++;
+ HASH_CHAR (len);
+ len = HASHMAXLEN;
+ }
+
+ while (len--)
+ {
+ HASH_CHAR (*string++);
}
return sum;
}
compare (entry, str, hash)
struct stringtab_entry *entry;
CONST char *str;
- int hash;
+ unsigned int hash;
{
- if (hash == entry->hash)
- return 0;
- if (hash > entry->hash)
- return 1;
- if (hash < entry->hash)
- return -1;
- abort ();
+ return hash - entry->hash;
}
#ifdef GATHER_STATISTICS
int check;
{
struct stringtab_entry **ep;
- struct stringtab_entry *entry;
- int hashval, len;
+ register struct stringtab_entry *entry;
+ unsigned int hashval, len;
if (str[0] == 0)
{
zero. With a balanced tree, this wouldn't be very useful, but without it,
we might get a more even split at the top level, instead of skewing it
badly should hash("/usr/lib/crt0.o") (or whatever) be far from zero. */
- hashval = hash (str) ^ tab->hash_zero;
+ hashval = hash (str, len) ^ tab->hash_zero;
ep = &tab->strings;
if (!*ep)
{
while (*ep)
{
- int cmp;
+ register int cmp;
+
entry = *ep;
#ifdef GATHER_STATISTICS
tab->n_compares++;
#endif
cmp = compare (entry, str, hashval);
- if (cmp == 0)
+ /* The not-equal cases are more frequent, so check them first. */
+ if (cmp > 0)
+ ep = &entry->greater;
+ else if (cmp < 0)
+ ep = &entry->less;
+ else
{
if (entry->string == str)
{
#endif
goto match;
}
- if (!strcmp (entry->string, str))
+ /* Compare the first bytes to save a function call if they
+ don't match. */
+ if (entry->string[0] == str[0] && !strcmp (entry->string, str))
{
match:
#ifdef GATHER_STATISTICS
#endif
ep = &entry->greater;
}
- else if (cmp > 0)
- ep = &entry->greater;
- else
- /* cmp < 0 */
- ep = &entry->less;
}
/* If we get here, nothing that's in the table already matched.
EP points to the `next' field at the end of the chain; stick a
new entry on here. */
add_it:
- entry = (struct stringtab_entry *) bfd_alloc_by_size_t (abfd,
- sizeof (struct stringtab_entry));
+ entry = (struct stringtab_entry *)
+ bfd_alloc_by_size_t (abfd, sizeof (struct stringtab_entry));
entry->less = entry->greater = 0;
entry->hash = hashval;
double n_compares = tab->n_compares;
double avg_compares = n_compares / n_syms;
/* The second value here should usually be near one. */
- fprintf (stderr, "\t average %f per symbol (%f * log2 nstrings)\n",
+ fprintf (stderr,
+ "\t average %f comparisons per symbol (%f * log2 nstrings)\n",
avg_compares, avg_compares / log2 (count));
}
}