from ralphc: recognize some mips variants
[deliverable/binutils-gdb.git] / bfd / coff-mips.c
index 210a493f95cfb55a5a9319db00287851282db8dc..082f6ba748e653b43afb22436b9d3510cac8822e 100644 (file)
@@ -191,7 +191,7 @@ DEFUN (ecoff_new_section_hook, (abfd, section),
     section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
   else if (strcmp (section->name, _BSS) == 0
           || strcmp (section->name, _SBSS) == 0)
-    section->flags |= SEC_ALLOC | SEC_IS_COMMON;
+    section->flags |= SEC_ALLOC;
 
   /* Probably any other section name is SEC_NEVER_LOAD, but I'm
      uncertain about .init on some systems and I don't know how shared
@@ -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; \
@@ -518,6 +531,15 @@ DEFUN (ecoff_slurp_symbolic_info, (abfd),
 /* ECOFF symbol table routines.  The ECOFF symbol table is described
    in gcc/mips-tfile.c.  */
 
+/* ECOFF uses two common sections.  One is the usual one, and the
+   other is for small objects.  All the small objects are kept
+   together, and then referenced via the gp pointer, which yields
+   faster assembler code.  This is what we use for the small common
+   section.  */
+static asection ecoff_scom_section;
+static asymbol ecoff_scom_symbol;
+static asymbol *ecoff_scom_symbol_ptr;
+
 /* Create an empty symbol.  */
 
 static asymbol *
@@ -563,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;
@@ -576,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");
@@ -588,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");
@@ -603,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:
@@ -618,7 +650,8 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
       break;
     case scSBss:
       asym->section = bfd_make_section_old_way (abfd, ".sbss");
-      asym->value -= asym->section->vma;
+      if (! ext)
+       asym->value -= asym->section->vma;
       break;
     case scRData:
       asym->section = bfd_make_section_old_way (abfd, ".rdata");
@@ -631,8 +664,21 @@ DEFUN (ecoff_set_symbol_info, (abfd, ecoff_sym, asym, ext),
       asym->section = &bfd_com_section;
       break;
     case scSCommon:
-      asym->section = bfd_make_section_old_way (abfd, ".sbss");
-      asym->value -= asym->section->vma;
+      if (ecoff_scom_section.name == NULL)
+       {
+         /* Initialize the small common section.  */
+         ecoff_scom_section.name = "*SCOM*";
+         ecoff_scom_section.flags = SEC_IS_COMMON;
+         ecoff_scom_section.output_section = &ecoff_scom_section;
+         ecoff_scom_section.symbol = &ecoff_scom_symbol;
+         ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr;
+         ecoff_scom_symbol.name = "*SCOM*";
+         ecoff_scom_symbol.flags = BSF_SECTION_SYM;
+         ecoff_scom_symbol.section = &ecoff_scom_section;
+         ecoff_scom_symbol_ptr = &ecoff_scom_symbol;
+       }
+      asym->section = &ecoff_scom_section;
+      asym->flags = 0;
       break;
     case scVarRegister:
     case scVariant:
@@ -640,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");
@@ -1368,23 +1416,57 @@ DEFUN (ecoff_swap_reloc_out, (abfd, src, dst),
   return RELSZ;
 }
 
+/* ECOFF relocs are either against external symbols, or against
+   sections.  If we are producing relocateable output, and the reloc
+   is against an external symbol, the resulting reloc will also be
+   against the same symbol.  In such a case, we don't want to change
+   anything about the way the reloc is handled, since it will all be
+   done at final link time.  Rather than put special case code into
+   bfd_perform_relocation, all the reloc types use this howto
+   function.  It just short circuits the reloc if producing
+   relocateable output against an external symbol.  */
+
+static bfd_reloc_status_type
+ecoff_generic_reloc (abfd,
+                    reloc_entry,
+                    symbol,
+                    data,
+                    input_section,
+                    output_bfd)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+{
+  if (output_bfd != (bfd *) NULL
+      && (symbol->flags & BSF_SECTION_SYM) == 0)
+    {
+      reloc_entry->address += input_section->output_offset;
+      return bfd_reloc_ok;
+    }
+
+  return bfd_reloc_continue;
+}
+
 /* Do a REFHI relocation.  The next reloc must be the corresponding
    REFLO.  This has to be done in a function so that carry is handled
    correctly.  */
 
 static bfd_reloc_status_type
-DEFUN (ecoff_refhi_reloc, (abfd,
-                          reloc_entry,
-                          symbol,
-                          data,
-                          input_section,
-                          output_bfd),
-       bfd *abfd AND
-       arelent *reloc_entry AND
-       asymbol *symbol AND
-       PTR data AND
-       asection *input_section AND
-       bfd *output_bfd)
+ecoff_refhi_reloc (abfd,
+                  reloc_entry,
+                  symbol,
+                  data,
+                  input_section,
+                  output_bfd)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
 {
   bfd_reloc_status_type ret;
   arelent *rello;
@@ -1393,6 +1475,15 @@ DEFUN (ecoff_refhi_reloc, (abfd,
   unsigned long val;
   unsigned long vallo;
 
+  /* If we're relocating, and this an external symbol, we don't want
+     to change anything.  */
+  if (output_bfd != (bfd *) NULL
+      && (symbol->flags & BSF_SECTION_SYM) == 0)
+    {
+      reloc_entry->address += input_section->output_offset;
+      return bfd_reloc_ok;
+    }
+
   ret = bfd_reloc_ok;
   if (symbol->section == &bfd_und_section
       && output_bfd == (bfd *) NULL)
@@ -1407,12 +1498,8 @@ DEFUN (ecoff_refhi_reloc, (abfd,
   else
     relocation = symbol->value;
 
-  if (output_bfd == (bfd *) NULL)
-    {
-      relocation += symbol->section->output_section->vma;
-      relocation += symbol->section->output_offset;
-    }
-
+  relocation += symbol->section->output_section->vma;
+  relocation += symbol->section->output_offset;
   relocation += reloc_entry->addend;
 
   if (reloc_entry->address > input_section->_cooked_size)
@@ -1446,24 +1533,33 @@ DEFUN (ecoff_refhi_reloc, (abfd,
    the offset from the gp register.  */
 
 static bfd_reloc_status_type
-DEFUN (ecoff_gprel_reloc, (abfd,
-                          reloc_entry,
-                          symbol,
-                          data,
-                          input_section,
-                          output_bfd),
-       bfd *abfd AND
-       arelent *reloc_entry AND
-       asymbol *symbol AND
-       PTR data AND
-       asection *input_section AND
-       bfd *output_bfd)
+ecoff_gprel_reloc (abfd,
+                  reloc_entry,
+                  symbol,
+                  data,
+                  input_section,
+                  output_bfd)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
 {
   boolean relocateable;
   bfd_vma relocation;
   unsigned long val;
   unsigned long insn;
 
+  /* If we're relocating, and this an external symbol, we don't want
+     to change anything.  */
+  if (output_bfd != (bfd *) NULL
+      && (symbol->flags & BSF_SECTION_SYM) == 0)
+    {
+      reloc_entry->address += input_section->output_offset;
+      return bfd_reloc_ok;
+    }
+
   if (output_bfd != (bfd *) NULL)
     relocateable = true;
   else
@@ -1482,7 +1578,7 @@ DEFUN (ecoff_gprel_reloc, (abfd,
      target data.  */
   if (ecoff_data (output_bfd)->gp == 0)
     {
-      if (relocateable)
+      if (relocateable != false)
        {
          /* Make up a value.  */
          ecoff_data (output_bfd)->gp =
@@ -1547,7 +1643,7 @@ DEFUN (ecoff_gprel_reloc, (abfd,
   insn = (insn &~ 0xffff) | (val & 0xffff);
   bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
 
-  if (relocateable)
+  if (relocateable != false)
     reloc_entry->address += input_section->output_offset;
 
   /* Make sure it fit in 16 bits.  */
@@ -1588,7 +1684,7 @@ static reloc_howto_type ecoff_howto_table[] =
         0,                     /* bitpos */
         false,                 /* absolute (obsolete) */
         true,                  /* complain_on_overflow */
-        0,                     /* special_function */
+        ecoff_generic_reloc,   /* special_function */
         "REFHALF",             /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -1604,7 +1700,7 @@ static reloc_howto_type ecoff_howto_table[] =
         0,                     /* bitpos */
         false,                 /* absolute (obsolete) */
         true,                  /* complain_on_overflow */
-        0,                     /* special_function */
+        ecoff_generic_reloc,   /* special_function */
         "REFWORD",             /* name */
         true,                  /* partial_inplace */
         0xffffffff,            /* src_mask */
@@ -1620,7 +1716,7 @@ static reloc_howto_type ecoff_howto_table[] =
         0,                     /* bitpos */
         false,                 /* absolute (obsolete) */
         true,                  /* complain_on_overflow */
-        0,                     /* special_function */
+        ecoff_generic_reloc,   /* special_function */
         "JMPADDR",             /* name */
         true,                  /* partial_inplace */
         0x3ffffff,             /* src_mask */
@@ -1653,7 +1749,7 @@ static reloc_howto_type ecoff_howto_table[] =
         0,                     /* bitpos */
         false,                 /* absolute (obsolete) */
         true,                  /* complain_on_overflow */
-        0,                     /* special_function */
+        ecoff_generic_reloc,   /* special_function */
         "REFLO",               /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
@@ -1823,7 +1919,7 @@ DEFUN (ecoff_canonicalize_reloc, (abfd, section, relptr, symbols),
           count++, chain = chain->next)
        *relptr++ = &chain->relent;
     }
-  else 
+  else
     { 
       arelent *tblptr;
 
@@ -1873,7 +1969,6 @@ DEFUN (ecoff_find_nearest_line, (abfd,
   unsigned char *line_ptr;
   unsigned char *line_end;
   int lineno;
-  SYMR proc_sym;
 
   /* If we're not in the .text section, we don't have any line
      numbers.  */
@@ -1966,13 +2061,38 @@ DEFUN (ecoff_find_nearest_line, (abfd,
   if (offset > 100)
     return false;
 
-  *filename_ptr = ecoff_data (abfd)->ss + fdr_ptr->issBase + fdr_ptr->rss;
-  ecoff_swap_sym_in (abfd,
-                    (ecoff_data (abfd)->external_sym
-                     + fdr_ptr->isymBase
-                     + pdr.isym),
-                    &proc_sym);
-  *functionname_ptr = ecoff_data (abfd)->ss + proc_sym.iss;
+  /* If fdr_ptr->rss is -1, then this file does not have full symbols,
+     at least according to gdb/mipsread.c.  */
+  if (fdr_ptr->rss == -1)
+    {
+      *filename_ptr = NULL;
+      if (pdr.isym == -1)
+       *functionname_ptr = NULL;
+      else
+       {
+         EXTR proc_ext;
+
+         ecoff_swap_ext_in (abfd,
+                            (ecoff_data (abfd)->external_ext
+                             + pdr.isym),
+                            &proc_ext);
+         *functionname_ptr = ecoff_data (abfd)->ssext + proc_ext.asym.iss;
+       }
+    }
+  else
+    {
+      SYMR proc_sym;
+
+      *filename_ptr = ecoff_data (abfd)->ss + fdr_ptr->issBase + fdr_ptr->rss;
+      ecoff_swap_sym_in (abfd,
+                        (ecoff_data (abfd)->external_sym
+                         + fdr_ptr->isymBase
+                         + pdr.isym),
+                        &proc_sym);
+      *functionname_ptr = (ecoff_data (abfd)->ss
+                          + fdr_ptr->issBase
+                          + proc_sym.iss);
+    }
   *retline_ptr = lineno;
   return true;
 }
@@ -2235,14 +2355,6 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
   FDR *fdr_ptr;
   FDR *fdr_end;
   struct fdr_ext *fdr_out;
-  long iss;
-  long isym;
-  long iline;
-  long iopt;
-  long ipdr;
-  long iaux;
-  long irfd;
-  long cbline;
 
   input_bfd = seclet->u.indirect.section->owner;
 
@@ -2443,17 +2555,6 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
      ifd values.  */
   input_ecoff->ifdbase = output_symhdr->ifdMax;
 
-  /* Step through the FDR's of input_bfd, adjust the offsets, and
-     swap them out.  */
-  iss = output_symhdr->issMax;
-  isym = output_symhdr->isymMax;
-  iline = output_symhdr->ilineMax;
-  iopt = output_symhdr->ioptMax;
-  ipdr = output_symhdr->ipdMax;
-  iaux = output_symhdr->iauxMax;
-  irfd = output_symhdr->crfd;
-  cbline = output_symhdr->cbLine;
-
   fdr_ptr = input_ecoff->fdr;
   fdr_end = fdr_ptr + input_symhdr->ifdMax;
   fdr_out = output_ecoff->external_fdr + output_symhdr->ifdMax;
@@ -2469,20 +2570,13 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
                 + seclet->offset
                 + (fdr_ptr->adr - input_ecoff->fdr->adr));
 
-      fdr.issBase = iss;
-      iss += fdr.cbSs;
-      fdr.isymBase = isym;
-      isym += fdr.csym;
-      fdr.ilineBase = iline;
-      iline += fdr.cline;
-      fdr.ioptBase = iopt;
-      iopt += fdr.copt;
-      fdr.ipdFirst = ipdr;
-      ipdr += fdr.cpd;
-      fdr.iauxBase = iaux;
-      iaux += fdr.caux;
-      fdr.rfdBase = irfd;
-      irfd += fdr.crfd;
+      fdr.issBase += output_symhdr->issMax;
+      fdr.isymBase += output_symhdr->isymMax;
+      fdr.ilineBase += output_symhdr->ilineMax;
+      fdr.ioptBase += output_symhdr->ioptMax;
+      fdr.ipdFirst += output_symhdr->ipdMax;
+      fdr.iauxBase += output_symhdr->iauxMax;
+      fdr.rfdBase += output_symhdr->crfd;
 
       /* If there are no RFD's, we are going to add some.  We don't
         want to adjust irfd for this, so that all the FDR's can share
@@ -2491,10 +2585,7 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
        fdr.crfd = input_symhdr->ifdMax;
 
       if (fdr.cbLine != 0)
-       {
-         fdr.cbLineOffset = cbline;
-         cbline += fdr.cbLine;
-       }
+       fdr.cbLineOffset += output_symhdr->cbLine;
 
       ecoff_swap_fdr_out (output_bfd, &fdr, fdr_out);
     }
@@ -2562,15 +2653,6 @@ DEFUN (ecoff_get_debug, (output_bfd, seclet, section),
   output_symhdr->issMax += input_symhdr->issMax;
   output_symhdr->ifdMax += input_symhdr->ifdMax;
 
-  /* Double check that the counts we got by stepping through the FDR's
-     match the counts we got from input_symhdr.  We don't check iss or
-     cbline because they are rounded.  */
-  BFD_ASSERT (output_symhdr->isymMax == isym
-             && output_symhdr->ilineMax == iline
-             && output_symhdr->ioptMax == iopt
-             && output_symhdr->ipdMax == ipdr
-             && output_symhdr->iauxMax == iaux);
-
   return true;
 }
 
@@ -2994,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;
@@ -3305,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
@@ -3317,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'
@@ -3334,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
@@ -3419,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));
@@ -3452,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;
@@ -3460,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;
 
@@ -3489,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));
@@ -3510,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.  */
@@ -3536,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;
 }
This page took 0.034014 seconds and 4 git commands to generate.