* coffgen.c (coff_renumber_symbols): Sort common symbols with
[binutils-gdb.git] / bfd / coffgen.c
index fe3676b0ad84e7408c76c0221fbdc62ba99758fd..cb9b2ba630cc636c2b6439b2be041f50adf7af6e 100644 (file)
@@ -329,6 +329,147 @@ coff_get_symtab (abfd, alocation)
   return bfd_get_symcount (abfd);
 }
 
+/* Get the name of a symbol.  The caller must pass in a buffer of size
+   >= SYMNMLEN + 1.  */
+
+const char *
+_bfd_coff_internal_syment_name (abfd, sym, buf)
+     bfd *abfd;
+     const struct internal_syment *sym;
+     char *buf;
+{
+  /* FIXME: It's not clear this will work correctly if sizeof
+     (_n_zeroes) != 4.  */
+  if (sym->_n._n_n._n_zeroes != 0
+      || sym->_n._n_n._n_offset == 0)
+    {
+      memcpy (buf, sym->_n._n_name, SYMNMLEN);
+      buf[SYMNMLEN] = '\0';
+      return buf;
+    }
+  else
+    {
+      const char *strings;
+
+      BFD_ASSERT (sym->_n._n_n._n_offset >= STRING_SIZE_SIZE);
+      strings = obj_coff_strings (abfd);
+      if (strings == NULL)
+       {
+         strings = _bfd_coff_read_string_table (abfd);
+         if (strings == NULL)
+           return NULL;
+       }
+      return strings + sym->_n._n_n._n_offset;
+    }
+}
+
+/* Read in and swap the relocs.  This returns a buffer holding the
+   relocs for section SEC in file ABFD.  If CACHE is true and
+   INTERNAL_RELOCS is NULL, the relocs read in will be saved in case
+   the function is called again.  If EXTERNAL_RELOCS is not NULL, it
+   is a buffer large enough to hold the unswapped relocs.  If
+   INTERNAL_RELOCS is not NULL, it is a buffer large enough to hold
+   the swapped relocs.  If REQUIRE_INTERNAL is true, then the return
+   value must be INTERNAL_RELOCS.  The function returns NULL on error.  */
+
+struct internal_reloc *
+_bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs,
+                               require_internal, internal_relocs)
+     bfd *abfd;
+     asection *sec;
+     boolean cache;
+     bfd_byte *external_relocs;
+     boolean require_internal;
+     struct internal_reloc *internal_relocs;
+{
+  bfd_size_type relsz;
+  bfd_byte *free_external = NULL;
+  struct internal_reloc *free_internal = NULL;
+  bfd_byte *erel;
+  bfd_byte *erel_end;
+  struct internal_reloc *irel;
+
+  if (coff_section_data (abfd, sec) != NULL
+      && coff_section_data (abfd, sec)->relocs != NULL)
+    {
+      if (! require_internal)
+       return coff_section_data (abfd, sec)->relocs;
+      memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs,
+             sec->reloc_count * sizeof (struct internal_reloc));
+      return internal_relocs;
+    }
+
+  relsz = bfd_coff_relsz (abfd);
+
+  if (external_relocs == NULL)
+    {
+      free_external = (bfd_byte *) malloc (sec->reloc_count * relsz);
+      if (free_external == NULL && sec->reloc_count > 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+      external_relocs = free_external;
+    }
+
+  if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
+      || (bfd_read (external_relocs, relsz, sec->reloc_count, abfd)
+         != relsz * sec->reloc_count))
+    goto error_return;
+
+  if (internal_relocs == NULL)
+    {
+      free_internal = ((struct internal_reloc *)
+                      malloc (sec->reloc_count
+                              * sizeof (struct internal_reloc)));
+      if (free_internal == NULL && sec->reloc_count > 0)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+      internal_relocs = free_internal;
+    }
+
+  /* Swap in the relocs.  */
+  erel = external_relocs;
+  erel_end = erel + relsz * sec->reloc_count;
+  irel = internal_relocs;
+  for (; erel < erel_end; erel += relsz, irel++)
+    bfd_coff_swap_reloc_in (abfd, (PTR) erel, (PTR) irel);
+
+  if (free_external != NULL)
+    {
+      free (free_external);
+      free_external = NULL;
+    }
+
+  if (cache && free_internal != NULL)
+    {
+      if (coff_section_data (abfd, sec) == NULL)
+       {
+         sec->used_by_bfd =
+           (PTR) bfd_zalloc (abfd,
+                             sizeof (struct coff_section_tdata));
+         if (sec->used_by_bfd == NULL)
+           {
+             bfd_set_error (bfd_error_no_memory);
+             goto error_return;
+           }
+         coff_section_data (abfd, sec)->contents = NULL;
+       }
+      coff_section_data (abfd, sec)->relocs = free_internal;
+    }
+
+  return internal_relocs;
+
+ error_return:
+  if (free_external != NULL)
+    free (free_external);
+  if (free_internal != NULL)
+    free (free_internal);
+  return NULL;
+}
+
 /* Set lineno_count for the output sections of a COFF file.  */
 
 int
@@ -361,7 +502,11 @@ coff_count_linenumbers (abfd)
        {
          coff_symbol_type *q = coffsymbol (q_maybe);
 
-         if (q->lineno != NULL)
+         /* The AIX 4.1 compiler can sometimes generate line numbers
+             attached to debugging symbols.  We try to simply ignore
+             those here.  */
+         if (q->lineno != NULL
+             && q->symbol.section->owner != NULL)
            {
              /* This symbol has line numbers.  Increment the owning
                 section's linenumber count.  */
@@ -487,25 +632,27 @@ coff_renumber_symbols (bfd_ptr, first_undef)
       }
     bfd_ptr->outsymbols = newsyms;
     for (i = 0; i < symbol_count; i++)
-      if (!bfd_is_und_section (symbol_ptr_ptr[i]->section)
-         && ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL
-                                          | BSF_NOT_AT_END
-                                          | BSF_FUNCTION))
-             != BSF_GLOBAL))
+      if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) != 0
+         || (!bfd_is_und_section (symbol_ptr_ptr[i]->section)
+             && !bfd_is_com_section (symbol_ptr_ptr[i]->section)
+             && ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_FUNCTION))
+                 != BSF_GLOBAL)))
        *newsyms++ = symbol_ptr_ptr[i];
 
     for (i = 0; i < symbol_count; i++)
       if (!bfd_is_und_section (symbol_ptr_ptr[i]->section)
-         && ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL
-                                          | BSF_NOT_AT_END
-                                          | BSF_FUNCTION))
-             == BSF_GLOBAL))
+         && (bfd_is_com_section (symbol_ptr_ptr[i]->section)
+             || ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL
+                                              | BSF_NOT_AT_END
+                                              | BSF_FUNCTION))
+                 == BSF_GLOBAL)))
        *newsyms++ = symbol_ptr_ptr[i];
 
     *first_undef = newsyms - bfd_ptr->outsymbols;
 
     for (i = 0; i < symbol_count; i++)
-      if (bfd_is_und_section (symbol_ptr_ptr[i]->section))
+      if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0
+         && bfd_is_und_section (symbol_ptr_ptr[i]->section))
        *newsyms++ = symbol_ptr_ptr[i];
     *newsyms = (asymbol *) NULL;
     symbol_ptr_ptr = bfd_ptr->outsymbols;
@@ -576,6 +723,18 @@ coff_mangle_symbols (bfd_ptr)
                ((combined_entry_type *) s->u.syment.n_value)->offset;
              s->fix_value = 0;
            }
+         if (s->fix_line)
+           {
+             /* The value is the offset into the line number entries
+                 for the symbol's section.  On output, the symbol's
+                 section should be N_DEBUG.  */
+             s->u.syment.n_value =
+               (coff_symbol_ptr->symbol.section->output_section->line_filepos
+                + s->u.syment.n_value * bfd_coff_linesz (bfd_ptr));
+             coff_symbol_ptr->symbol.section =
+               coff_section_from_bfd_index (bfd_ptr, N_DEBUG);
+             BFD_ASSERT (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING);
+           }
          for (i = 0; i < s->u.syment.n_numaux; i++)
            {
              combined_entry_type *a = s + i + 1;
@@ -624,7 +783,8 @@ coff_fix_symbol_name (abfd, symbol, native, string_size_p,
     }
   name_length = strlen (name);
 
-  if (native->u.syment.n_sclass == C_FILE)
+  if (native->u.syment.n_sclass == C_FILE
+      && native->u.syment.n_numaux > 0)
     {
       strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN);
       auxent = &(native + 1)->u.auxent;
@@ -652,7 +812,7 @@ coff_fix_symbol_name (abfd, symbol, native, string_size_p,
        }
     }
   else
-    {                          /* NOT A C_FILE SYMBOL */
+    {
       if (name_length <= SYMNMLEN)
        {
          /* This name will fit into the symbol neatly */
@@ -728,7 +888,8 @@ coff_write_symbol (abfd, symbol, native, written, string_size_p,
   if (native->u.syment.n_sclass == C_FILE)
     symbol->flags |= BSF_DEBUGGING;
 
-  if (symbol->flags & BSF_DEBUGGING)
+  if (symbol->flags & BSF_DEBUGGING
+      && bfd_is_abs_section (symbol->section))
     {
       native->u.syment.n_scnum = N_DEBUG;
     }
@@ -880,7 +1041,7 @@ coff_write_native_symbol (abfd, symbol, written, string_size_p,
   /* If this symbol has an associated line number, we must store the
      symbol index in the line number field.  We also tag the auxent to
      point to the right place in the lineno table.  */
-  if (lineno && !symbol->done_lineno)
+  if (lineno && !symbol->done_lineno && symbol->symbol.section->owner != NULL)
     {
       unsigned int count = 0;
       lineno[count].u.offset = *written;
@@ -1024,7 +1185,8 @@ coff_write_symbols (abfd)
                 Don't write it into the string table.  */
              maxlen = name_length;
            }
-         else if (c_symbol->native->u.syment.n_sclass == C_FILE)
+         else if (c_symbol->native->u.syment.n_sclass == C_FILE
+                  && c_symbol->native->u.syment.n_numaux > 0)
            maxlen = FILNMLEN;
          else
            maxlen = SYMNMLEN;
@@ -1321,7 +1483,7 @@ _bfd_coff_get_external_symbols (abfd)
 
   size = obj_raw_syment_count (abfd) * symesz;
 
-  syms = malloc (size);
+  syms = (PTR) malloc (size);
   if (syms == NULL && size != 0)
     {
       bfd_set_error (bfd_error_no_memory);
@@ -1379,7 +1541,16 @@ _bfd_coff_read_string_table (abfd)
 #endif
     }
 
-  strings = malloc (strsize);
+  if (strsize < STRING_SIZE_SIZE)
+    {
+      (*_bfd_error_handler)
+       ("%s: bad string table size %lu", bfd_get_filename (abfd),
+        (unsigned long) strsize);
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+    }
+
+  strings = (char *) malloc (strsize);
   if (strings == NULL)
     {
       bfd_set_error (bfd_error_no_memory);
@@ -1669,6 +1840,15 @@ coff_get_symbol_info (abfd, symbol, ret)
      symbol_info *ret;
 {
   bfd_symbol_info (symbol, ret);
+  if (coffsymbol (symbol)->native != NULL
+      && coffsymbol (symbol)->native->fix_value)
+    {
+      combined_entry_type *psym;
+
+      psym = ((combined_entry_type *)
+             coffsymbol (symbol)->native->u.syment.n_value);
+      ret->value = (bfd_vma) (psym - obj_raw_syments (abfd));
+    }
 }
 
 /* Print out information about COFF symbol.  */
@@ -1697,6 +1877,7 @@ coff_print_symbol (abfd, filep, symbol, how)
     case bfd_print_symbol_all:
       if (coffsymbol (symbol)->native)
        {
+         unsigned long val;
          unsigned int aux;
          combined_entry_type *combined = coffsymbol (symbol)->native;
          combined_entry_type *root = obj_raw_syments (abfd);
@@ -1704,6 +1885,13 @@ coff_print_symbol (abfd, filep, symbol, how)
 
          fprintf (file, "[%3ld]", (long) (combined - root));
 
+         if (! combined->fix_value)
+           val = (unsigned long) combined->u.syment.n_value;
+         else
+           val = ((unsigned long)
+                  ((combined_entry_type *) combined->u.syment.n_value
+                   - root));
+
          fprintf (file,
                   "(sec %2d)(fl 0x%02x)(ty %3x)(scl %3d) (nx %d) 0x%08lx %s",
                   combined->u.syment.n_scnum,
@@ -1711,7 +1899,7 @@ coff_print_symbol (abfd, filep, symbol, how)
                   combined->u.syment.n_type,
                   combined->u.syment.n_sclass,
                   combined->u.syment.n_numaux,
-                  (unsigned long) combined->u.syment.n_value,
+                  val,
                   symbol->name);
 
          for (aux = 0; aux < combined->u.syment.n_numaux; aux++)
@@ -1947,7 +2135,7 @@ coff_find_nearest_line (abfd, section, ignore_symbols, offset, filename_ptr,
       section->used_by_bfd =
        ((PTR) bfd_zalloc (abfd,
                           sizeof (struct coff_section_tdata)));
-      sec_data = section->used_by_bfd;
+      sec_data = (struct coff_section_tdata *) section->used_by_bfd;
     }
   if (sec_data != NULL)
     {