diff options
author | Ian Lance Taylor <ian@airs.com> | 1993-01-29 23:24:20 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 1993-01-29 23:24:20 +0000 |
commit | 23ba15b7754ac8ff788bdf0699203f4d52833261 (patch) | |
tree | d49747e3c370fd59bbcda5abc7c439dcf4e92979 /bfd/coff-mips.c | |
parent | f31cb329d51c1344be1d0aaef7276f653ba23c5b (diff) | |
download | gdb-23ba15b7754ac8ff788bdf0699203f4d52833261.zip gdb-23ba15b7754ac8ff788bdf0699203f4d52833261.tar.gz gdb-23ba15b7754ac8ff788bdf0699203f4d52833261.tar.bz2 |
Checkpoint. Can now create MIPS style armap hash tables. Fixed some
linker problems. The linker still needs to learn to put SCommon
symbols in .sbss rather than .bss.
Diffstat (limited to 'bfd/coff-mips.c')
-rw-r--r-- | bfd/coff-mips.c | 224 |
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; } |