aboutsummaryrefslogtreecommitdiff
path: root/bfd/coff-mips.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/coff-mips.c')
-rw-r--r--bfd/coff-mips.c224
1 files changed, 189 insertions, 35 deletions
diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c
index 85a9056..082f6ba 100644
--- a/bfd/coff-mips.c
+++ b/bfd/coff-mips.c
@@ -435,17 +435,32 @@ DEFUN (ecoff_slurp_symbolic_info, (abfd),
+ internal_symhdr->iextMax);
/* Read all the symbolic information at once. */
- raw_size = (internal_symhdr->cbLine * sizeof (unsigned char)
- + internal_symhdr->idnMax * sizeof (struct dnr_ext)
- + internal_symhdr->ipdMax * sizeof (struct pdr_ext)
- + internal_symhdr->isymMax * sizeof (struct sym_ext)
- + internal_symhdr->ioptMax * sizeof (struct opt_ext)
- + internal_symhdr->iauxMax * sizeof (union aux_ext)
- + internal_symhdr->issMax * sizeof (char)
- + internal_symhdr->issExtMax * sizeof (char)
- + internal_symhdr->ifdMax * sizeof (struct fdr_ext)
- + internal_symhdr->crfd * sizeof (struct rfd_ext)
- + internal_symhdr->iextMax * sizeof (struct ext_ext));
+ raw_base = ecoff_data (abfd)->sym_filepos + sizeof (struct hdr_ext);
+
+ if (internal_symhdr->cbExtOffset != 0)
+ raw_size = (internal_symhdr->cbExtOffset
+ - raw_base
+ + internal_symhdr->iextMax * sizeof (struct ext_ext));
+ else
+ {
+ long cbline, issmax, issextmax;
+
+ cbline = (internal_symhdr->cbLine + 3) &~ 4;
+ issmax = (internal_symhdr->issMax + 3) &~ 4;
+ issextmax = (internal_symhdr->issExtMax + 3) &~ 4;
+ raw_size = (cbline * sizeof (unsigned char)
+ + internal_symhdr->idnMax * sizeof (struct dnr_ext)
+ + internal_symhdr->ipdMax * sizeof (struct pdr_ext)
+ + internal_symhdr->isymMax * sizeof (struct sym_ext)
+ + internal_symhdr->ioptMax * sizeof (struct opt_ext)
+ + internal_symhdr->iauxMax * sizeof (union aux_ext)
+ + issmax * sizeof (char)
+ + issextmax * sizeof (char)
+ + internal_symhdr->ifdMax * sizeof (struct fdr_ext)
+ + internal_symhdr->crfd * sizeof (struct rfd_ext)
+ + internal_symhdr->iextMax * sizeof (struct ext_ext));
+ }
+
if (raw_size == 0)
{
ecoff_data (abfd)->sym_filepos = 0;
@@ -468,8 +483,6 @@ DEFUN (ecoff_slurp_symbolic_info, (abfd),
ecoff_data (abfd)->raw_syments = raw;
/* Get pointers for the numeric offsets in the HDRR structure. */
- raw_base = ecoff_data (abfd)->sym_filepos + sizeof (struct hdr_ext);
-
#define FIX(off1, off2, type) \
if (internal_symhdr->off1 == 0) \
ecoff_data (abfd)->off2 = (type *) NULL; \
@@ -572,6 +585,7 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
case stProc:
case stStaticProc:
case stBlock:
+ case stNil:
break;
default:
asym->flags = BSF_DEBUGGING;
@@ -585,7 +599,11 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
switch (ecoff_sym->sc)
{
case scNil:
- asym->flags = BSF_DEBUGGING;
+ /* Used for compiler generated labels. Leave them in the
+ debugging section, and mark them as local. If BSF_DEBUGGING
+ is set, then nm does not display them for some reason. If no
+ flags are set then the linker whines about them. */
+ asym->flags = BSF_LOCAL;
break;
case scText:
asym->section = bfd_make_section_old_way (abfd, ".text");
@@ -597,7 +615,10 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
break;
case scBss:
if (ext)
- asym->section = &bfd_com_section;
+ {
+ asym->section = &bfd_com_section;
+ asym->flags = 0;
+ }
else
{
asym->section = bfd_make_section_old_way (abfd, ".bss");
@@ -612,6 +633,8 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
break;
case scUndefined:
asym->section = &bfd_und_section;
+ asym->flags = 0;
+ asym->value = 0;
break;
case scCdbLocal:
case scBits:
@@ -655,6 +678,7 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
ecoff_scom_symbol_ptr = &ecoff_scom_symbol;
}
asym->section = &ecoff_scom_section;
+ asym->flags = 0;
break;
case scVarRegister:
case scVariant:
@@ -662,6 +686,8 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
break;
case scSUndefined:
asym->section = &bfd_und_section;
+ asym->flags = 0;
+ asym->value = 0;
break;
case scInit:
asym->section = bfd_make_section_old_way (abfd, ".init");
@@ -3050,7 +3076,7 @@ DEFUN (ecoff_write_object_contents, (abfd),
ecoff_data (abfd)->sym_filepos = sym_base;
- text_size = 0;
+ text_size = FILHSZ + AOUTSZ + abfd->section_count * SCNHSZ;
text_start = 0;
data_size = 0;
data_start = 0;
@@ -3361,9 +3387,7 @@ DEFUN (ecoff_write_object_contents, (abfd),
ordering in the armap and the contents.
The first four bytes in the armap are the number of symbol
- definitions. This always seems to be a power of two, presumably
- because ranlib uses a hash table of some sort. I don't know what
- the hashing scheme is at the moment.
+ definitions. This is always a power of two.
This is followed by the symbol definitions. Each symbol definition
occupies 8 bytes. The first four bytes are the offset from the
@@ -3373,11 +3397,20 @@ DEFUN (ecoff_write_object_contents, (abfd),
are 0, then this is not actually a symbol definition, and it should
be ignored.
+ The symbols are hashed into the armap with a closed hashing scheme.
+ See the functions below for the details of the algorithm.
+
+ We could use the hash table when looking up symbols in a library.
+ This would require a new BFD target entry point to replace the
+ bfd_get_next_mapent function used by the linker.
+
After the symbol definitions comes four bytes holding the size of
the string table, followed by the string table itself. */
/* The name of an archive headers looks like this:
- __________E[BL]E[BL]_ (with a trailing space). */
+ __________E[BL]E[BL]_ (with a trailing space).
+ The trailing space is changed to an X if the archive is changed to
+ indicate that the armap is out of date. */
#define ARMAP_BIG_ENDIAN 'B'
#define ARMAP_LITTLE_ENDIAN 'L'
@@ -3390,6 +3423,31 @@ DEFUN (ecoff_write_object_contents, (abfd),
#define ARMAP_END_INDEX 14
#define ARMAP_END "_ "
+/* This is a magic number used in the hashing algorithm. */
+#define ARMAP_HASH_MAGIC 0x9dd68ab5
+
+/* This returns the hash value to use for a string. It also sets
+ *REHASH to the rehash adjustment if the first slot is taken. SIZE
+ is the number of entries in the hash table, and HLOG is the log
+ base 2 of SIZE. */
+
+static unsigned int
+ecoff_armap_hash (s, rehash, size, hlog)
+ CONST char *s;
+ unsigned int *rehash;
+ unsigned int size;
+ unsigned int hlog;
+{
+ unsigned int hash;
+
+ hash = *s++;
+ while (*s != '\0')
+ hash = ((hash >> 27) | (hash << 5)) + *s++;
+ hash *= ARMAP_HASH_MAGIC;
+ *rehash = (hash & (size - 1)) | 1;
+ return hash >> (32 - hlog);
+}
+
/* Read in the armap. */
static boolean
@@ -3475,9 +3533,51 @@ DEFUN (ecoff_slurp_armap, (abfd),
ardata->symdefs = (carsym *) symdef_ptr;
stringbase = raw_ptr + count * (2 * LONG_SIZE) + LONG_SIZE;
+#ifdef CHECK_ARMAP_HASH
+ {
+ unsigned int hlog;
+
+ /* Double check that I have the hashing algorithm right by making
+ sure that every symbol can be looked up successfully. */
+ hlog = 0;
+ for (i = 1; i < count; i <<= 1)
+ hlog++;
+ BFD_ASSERT (i == count);
+
+ for (i = 0; i < count; i++, raw_ptr += 2 * LONG_SIZE)
+ {
+ unsigned int name_offset, file_offset;
+ unsigned int hash, rehash, srch;
+
+ name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr);
+ file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + LONG_SIZE));
+ if (file_offset == 0)
+ continue;
+ hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count,
+ hlog);
+ if (hash == i)
+ continue;
+
+ /* See if we can rehash to this location. */
+ for (srch = (hash + rehash) & (count - 1);
+ srch != hash && srch != i;
+ srch = (srch + rehash) & (count - 1))
+ BFD_ASSERT (bfd_h_get_32 (abfd,
+ (PTR) (raw_armap
+ + LONG_SIZE
+ + (srch * 2 * LONG_SIZE)
+ + LONG_SIZE))
+ != 0);
+ BFD_ASSERT (srch == i);
+ }
+ }
+
+ raw_ptr = raw_armap + LONG_SIZE;
+#endif /* CHECK_ARMAP_HASH */
+
for (i = 0; i < count; i++, raw_ptr += 2 * LONG_SIZE)
{
- unsigned long name_offset, file_offset;
+ unsigned int name_offset, file_offset;
name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr);
file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + LONG_SIZE));
@@ -3508,6 +3608,7 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
unsigned int orl_count AND
int stridx)
{
+ unsigned int hashsize, hashlog;
unsigned int symdefsize;
int padit;
unsigned int stringsize;
@@ -3516,16 +3617,23 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
struct ar_hdr hdr;
struct stat statbuf;
unsigned int i;
- bfd_byte temp[4];
+ bfd_byte temp[LONG_SIZE];
+ bfd_byte *hashtable;
bfd *current;
bfd *last_elt;
- symdefsize = orl_count * 8;
+ /* Ultrix appears to use as a hash table size the least power of two
+ greater than twice the number of entries. */
+ for (hashlog = 0; (1 << hashlog) <= 2 * orl_count; hashlog++)
+ ;
+ hashsize = 1 << hashlog;
+
+ symdefsize = hashsize * 2 * LONG_SIZE;
padit = stridx % 2;
stringsize = stridx + padit;
/* Include 8 bytes to store symdefsize and stringsize in output. */
- mapsize = 4 + symdefsize + stringsize + 4;
+ mapsize = LONG_SIZE + symdefsize + stringsize + LONG_SIZE;
firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength;
@@ -3545,7 +3653,9 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
/* Write the timestamp of the archive header to be just a little bit
later than the timestamp of the file, otherwise the linker will
- complain that the index is out of date. */
+ complain that the index is out of date. Actually, the Ultrix
+ linker just checks the archive name; the GNU linker may check the
+ date. */
if (stat (abfd->filename, &statbuf) < 0)
statbuf.st_mtime = time ((PTR) NULL);
sprintf (hdr.ar_date, "%ld", (long) (statbuf.st_mtime + 60));
@@ -3566,16 +3676,21 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
if (((char *)(&hdr))[i] == '\0')
(((char *)(&hdr))[i]) = ' ';
- bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd);
+ if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd)
+ != sizeof (struct ar_hdr))
+ return false;
- bfd_h_put_32 (abfd, symdefsize, temp);
- bfd_write (temp, 1, LONG_SIZE, abfd);
+ bfd_h_put_32 (abfd, hashsize, temp);
+ if (bfd_write (temp, 1, LONG_SIZE, abfd) != LONG_SIZE)
+ return false;
+ hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize);
+
current = abfd->archive_head;
last_elt = current;
for (i = 0; i < orl_count; i++)
{
- bfd_byte buff[8];
+ unsigned int hash, rehash;
/* Advance firstreal to the file position of this archive
element. */
@@ -3592,21 +3707,60 @@ DEFUN (ecoff_write_armap, (abfd, elength, map, orl_count, stridx),
last_elt = current;
- bfd_h_put_32 (abfd, map[i].namidx, buff);
- bfd_h_put_32 (abfd, firstreal, buff + LONG_SIZE);
- bfd_write (buff, 1, 2 * LONG_SIZE, abfd);
+ hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog);
+ if (bfd_h_get_32 (abfd, (PTR) (hashtable
+ + (hash * 2 * LONG_SIZE)
+ + LONG_SIZE))
+ != 0)
+ {
+ unsigned int srch;
+
+ /* The desired slot is already taken. */
+ for (srch = (hash + rehash) & (hashsize - 1);
+ srch != hash;
+ srch = (srch + rehash) & (hashsize - 1))
+ if (bfd_h_get_32 (abfd, (PTR) (hashtable
+ + (srch * 2 * LONG_SIZE)
+ + LONG_SIZE))
+ == 0)
+ break;
+
+ BFD_ASSERT (srch != hash);
+
+ hash = srch;
+ }
+
+ bfd_h_put_32 (abfd, map[i].namidx,
+ (PTR) (hashtable + hash * 2 * LONG_SIZE));
+ bfd_h_put_32 (abfd, firstreal,
+ (PTR) (hashtable + hash * 2 * LONG_SIZE + LONG_SIZE));
}
+ if (bfd_write (hashtable, 1, symdefsize, abfd) != symdefsize)
+ return false;
+
+ bfd_release (abfd, hashtable);
+
/* Now write the strings. */
bfd_h_put_32 (abfd, stringsize, temp);
- bfd_write (temp, 1, LONG_SIZE, abfd);
+ if (bfd_write (temp, 1, LONG_SIZE, abfd) != LONG_SIZE)
+ return false;
for (i = 0; i < orl_count; i++)
- bfd_write ((PTR) (*map[i].name), 1, strlen (*map[i].name) + 1, abfd);
+ {
+ bfd_size_type len;
+
+ len = strlen (*map[i].name) + 1;
+ if (bfd_write ((PTR) (*map[i].name), 1, len, abfd) != len)
+ return false;
+ }
/* The spec sez this should be a newline. But in order to be
bug-compatible for DECstation ar we use a null. */
if (padit)
- bfd_write ("\0", 1, 1, abfd);
+ {
+ if (bfd_write ("\0", 1, 1, abfd) != 1)
+ return false;
+ }
return true;
}