Add prototypes for static functions.
[binutils-gdb.git] / bfd / coffgen.c
index 14df3a3f72905a97eda66ea7143d52a42f58ec99..74414a15927203d83f3fa2dc5c15df289e6a3852 100644 (file)
@@ -1,5 +1,5 @@
 /* Support for the generic parts of COFF, for BFD.
-   Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -56,6 +56,17 @@ static boolean coff_write_native_symbol
 static void coff_pointerize_aux
   PARAMS ((bfd *, combined_entry_type *, combined_entry_type *,
           unsigned int, combined_entry_type *));
+static boolean make_a_section_from_file
+  PARAMS ((bfd *, struct internal_scnhdr *, unsigned int));
+static const bfd_target *coff_real_object_p
+  PARAMS ((bfd *, unsigned, struct internal_filehdr *, 
+          struct internal_aouthdr *));
+static void fixup_symbol_value
+  PARAMS ((bfd *, coff_symbol_type *, struct internal_syment *));
+static char *build_debug_section
+  PARAMS ((bfd *));
+static char *copy_name
+  PARAMS ((bfd *, char *, int));
 
 #define STRING_SIZE_SIZE (4)
 
@@ -70,12 +81,45 @@ make_a_section_from_file (abfd, hdr, target_index)
   asection *return_section;
   char *name;
 
-  /* Assorted wastage to null-terminate the name, thanks AT&T! */
-  name = bfd_alloc (abfd, sizeof (hdr->s_name) + 1);
+  name = NULL;
+
+  /* Handle long section names as in PE.  */
+  if (bfd_coff_long_section_names (abfd)
+      && hdr->s_name[0] == '/')
+    {
+      char buf[SCNNMLEN];
+      long strindex;
+      char *p;
+      const char *strings;
+
+      memcpy (buf, hdr->s_name + 1, SCNNMLEN - 1);
+      buf[SCNNMLEN - 1] = '\0';
+      strindex = strtol (buf, &p, 10);
+      if (*p == '\0' && strindex >= 0)
+       {
+         strings = _bfd_coff_read_string_table (abfd);
+         if (strings == NULL)
+           return false;
+         /* FIXME: For extra safety, we should make sure that
+             strindex does not run us past the end, but right now we
+             don't know the length of the string table.  */
+         strings += strindex;
+         name = bfd_alloc (abfd, strlen (strings) + 1);
+         if (name == NULL)
+           return false;
+         strcpy (name, strings);
+       }
+    }
+
   if (name == NULL)
-    return false;
-  strncpy (name, (char *) &hdr->s_name[0], sizeof (hdr->s_name));
-  name[sizeof (hdr->s_name)] = 0;
+    {
+      /* Assorted wastage to null-terminate the name, thanks AT&T! */
+      name = bfd_alloc (abfd, sizeof (hdr->s_name) + 1);
+      if (name == NULL)
+       return false;
+      strncpy (name, (char *) &hdr->s_name[0], sizeof (hdr->s_name));
+      name[sizeof (hdr->s_name)] = 0;
+    }
 
   return_section = bfd_make_section_anyway (abfd, name);
   if (return_section == NULL)
@@ -176,7 +220,8 @@ coff_real_object_p (abfd, nscns, internal_f, internal_a)
          bfd_coff_swap_scnhdr_in (abfd,
                                   (PTR) (external_sections + i * scnhsz),
                                   (PTR) & tmp);
-         make_a_section_from_file (abfd, &tmp, i + 1);
+         if (! make_a_section_from_file (abfd, &tmp, i + 1))
+           goto fail;
        }
     }
 
@@ -245,11 +290,6 @@ coff_object_p (abfd)
       bfd_coff_swap_aouthdr_in (abfd, opthdr, (PTR) & internal_a);
     }
 
-  /* Seek past the opt hdr stuff */
-  if (bfd_seek (abfd, (file_ptr) (internal_f.f_opthdr + filhsz), SEEK_SET)
-      != 0)
-    return NULL;
-
   return coff_real_object_p (abfd, nscns, &internal_f,
                             (internal_f.f_opthdr != 0
                              ? &internal_a
@@ -530,7 +570,8 @@ coff_symbol_from (ignore_abfd, symbol)
 }
 
 static void
-fixup_symbol_value (coff_symbol_ptr, syment)
+fixup_symbol_value (abfd, coff_symbol_ptr, syment)
+     bfd *abfd;
      coff_symbol_type *coff_symbol_ptr;
      struct internal_syment *syment;
 {
@@ -558,10 +599,11 @@ fixup_symbol_value (coff_symbol_ptr, syment)
          syment->n_scnum =
            coff_symbol_ptr->symbol.section->output_section->target_index;
 
-         syment->n_value =
-           coff_symbol_ptr->symbol.value +
-           coff_symbol_ptr->symbol.section->output_offset +
-           coff_symbol_ptr->symbol.section->output_section->vma;
+         syment->n_value = (coff_symbol_ptr->symbol.value
+                            + coff_symbol_ptr->symbol.section->output_offset);
+         if (! obj_pe (abfd))
+           syment->n_value +=
+             coff_symbol_ptr->symbol.section->output_section->vma;
        }
       else
        {
@@ -605,9 +647,8 @@ coff_renumber_symbols (bfd_ptr, first_undef)
     asymbol **newsyms;
     unsigned int i;
 
-    newsyms = (asymbol **) bfd_alloc_by_size_t (bfd_ptr,
-                                               sizeof (asymbol *)
-                                               * (symbol_count + 1));
+    newsyms = (asymbol **) bfd_alloc (bfd_ptr,
+                                     sizeof (asymbol *) * (symbol_count + 1));
     if (!newsyms)
       return false;
     bfd_ptr->outsymbols = newsyms;
@@ -620,11 +661,10 @@ coff_renumber_symbols (bfd_ptr, first_undef)
        *newsyms++ = symbol_ptr_ptr[i];
 
     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)
          && (bfd_is_com_section (symbol_ptr_ptr[i]->section)
-             || ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL
-                                              | BSF_NOT_AT_END
-                                              | BSF_FUNCTION))
+             || ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_FUNCTION))
                  == BSF_GLOBAL)))
        *newsyms++ = symbol_ptr_ptr[i];
 
@@ -659,7 +699,7 @@ coff_renumber_symbols (bfd_ptr, first_undef)
              /* Modify the symbol values according to their section and
                 type */
 
-             fixup_symbol_value (coff_symbol_ptr, &(s->u.syment));
+             fixup_symbol_value (bfd_ptr, coff_symbol_ptr, &(s->u.syment));
            }
          for (i = 0; i < s->u.syment.n_numaux + 1; i++)
            s[i].offset = native_index++;
@@ -974,8 +1014,9 @@ coff_write_alien_symbol (abfd, symbol, written, string_size_p,
       native->u.syment.n_scnum =
        symbol->section->output_section->target_index;
       native->u.syment.n_value = (symbol->value
-                                 + symbol->section->output_section->vma
                                  + symbol->section->output_offset);
+      if (! obj_pe (abfd))
+       native->u.syment.n_value += symbol->section->output_section->vma;
 
       /* Copy the any flags from the the file header into the symbol.
          FIXME: Why?  */
@@ -1084,6 +1125,24 @@ coff_write_symbols (abfd)
   debug_string_section = NULL;
   debug_string_size = 0;
 
+  /* If this target supports long section names, they must be put into
+     the string table.  This is supported by PE.  This code must
+     handle section names just as they are handled in
+     coff_write_object_contents.  */
+  if (bfd_coff_long_section_names (abfd))
+    {
+      asection *o;
+
+      for (o = abfd->sections; o != NULL; o = o->next)
+       {
+         size_t len;
+
+         len = strlen (o->name);
+         if (len > SCNNMLEN)
+           string_size += len + 1;
+       }
+    }
+
   /* Seek to the right place */
   if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0)
     return false;
@@ -1129,6 +1188,26 @@ coff_write_symbols (abfd)
 #endif
       if (bfd_write ((PTR) buffer, 1, sizeof (buffer), abfd) != sizeof (buffer))
        return false;
+
+      /* Handle long section names.  This code must handle section
+        names just as they are handled in coff_write_object_contents.  */
+      if (bfd_coff_long_section_names (abfd))
+       {
+         asection *o;
+
+         for (o = abfd->sections; o != NULL; o = o->next)
+           {
+             size_t len;
+
+             len = strlen (o->name);
+             if (len > SCNNMLEN)
+               {
+                 if (bfd_write (o->name, 1, len + 1, abfd) != len + 1)
+                   return false;
+               }
+           }
+       }
+
       for (p = abfd->outsymbols, i = 0;
           i < limit;
           i++, p++)
@@ -1298,7 +1377,7 @@ coff_section_symbol (abfd, name)
          combined_entry_type e[10];
        };
       struct foo *f;
-      f = (struct foo *) bfd_alloc_by_size_t (abfd, sizeof (*f));
+      f = (struct foo *) bfd_alloc (abfd, sizeof (*f));
       if (!f)
        {
          bfd_set_error (bfd_error_no_error);
@@ -1355,7 +1434,7 @@ coff_pointerize_aux (abfd, table_base, symbol, indaux, auxent)
   /* Otherwise patch up */
 #define N_TMASK coff_data (abfd)->local_n_tmask
 #define N_BTSHFT coff_data (abfd)->local_n_btshft
-  if ((ISFCN (type) || ISTAG (class) || class == C_BLOCK)
+  if ((ISFCN (type) || ISTAG (class) || class == C_BLOCK || class == C_FCN)
       && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0)
     {
       auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p =
@@ -1487,6 +1566,12 @@ _bfd_coff_read_string_table (abfd)
   if (obj_coff_strings (abfd) != NULL)
     return obj_coff_strings (abfd);
 
+  if (obj_sym_filepos (abfd) == 0)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return NULL;
+    }
+
   if (bfd_seek (abfd,
                (obj_sym_filepos (abfd)
                 + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd)),
@@ -1794,6 +1879,78 @@ coff_get_symbol_info (abfd, symbol, ret)
     }
 }
 
+/* Return the COFF syment for a symbol.  */
+
+boolean
+bfd_coff_get_syment (abfd, symbol, psyment)
+     bfd *abfd;
+     asymbol *symbol;
+     struct internal_syment *psyment;
+{
+  coff_symbol_type *csym;
+
+  csym = coff_symbol_from (abfd, symbol);
+  if (csym == NULL || csym->native == NULL)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
+    }
+
+  *psyment = csym->native->u.syment;
+
+  if (csym->native->fix_value)
+    psyment->n_value = ((combined_entry_type *) psyment->n_value
+                       - obj_raw_syments (abfd));
+
+  /* FIXME: We should handle fix_line here.  */
+
+  return true;
+}
+
+/* Return the COFF auxent for a symbol.  */
+
+boolean
+bfd_coff_get_auxent (abfd, symbol, indx, pauxent)
+     bfd *abfd;
+     asymbol *symbol;
+     int indx;
+     union internal_auxent *pauxent;
+{
+  coff_symbol_type *csym;
+  combined_entry_type *ent;
+
+  csym = coff_symbol_from (abfd, symbol);
+
+  if (csym == NULL
+      || csym->native == NULL
+      || indx >= csym->native->u.syment.n_numaux)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return false;
+    }
+
+  ent = csym->native + indx + 1;
+
+  *pauxent = ent->u.auxent;
+
+  if (ent->fix_tag)
+    pauxent->x_sym.x_tagndx.l =
+      ((combined_entry_type *) pauxent->x_sym.x_tagndx.p
+       - obj_raw_syments (abfd));
+
+  if (ent->fix_end)
+    pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l =
+      ((combined_entry_type *) pauxent->x_sym.x_fcnary.x_fcn.x_endndx.p
+       - obj_raw_syments (abfd));
+
+  if (ent->fix_scnlen)
+    pauxent->x_csect.x_scnlen.l =
+      ((combined_entry_type *) pauxent->x_csect.x_scnlen.p
+       - obj_raw_syments (abfd));
+
+  return true;
+}
+
 /* Print out information about COFF symbol.  */
 
 void
@@ -1925,6 +2082,19 @@ coff_print_symbol (abfd, filep, symbol, how)
     }
 }
 
+/* Return whether a symbol name implies a local symbol.  In COFF,
+   local symbols generally start with ``.L''.  Most targets use this
+   function for the is_local_label_name entry point, but some may
+   override it.  */
+
+boolean
+_bfd_coff_is_local_label_name (abfd, name)
+     bfd *abfd;
+     const char *name;
+{
+  return name[0] == '.' && name[1] == 'L';
+}
+
 /* Provided a BFD, a section and an offset into the section, calculate
    and return the name of the source file and the line nearest to the
    wanted location.  */
@@ -1974,6 +2144,9 @@ coff_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
 
   /* Find the first C_FILE symbol.  */
   p = cof->raw_syments;
+  if (!p)
+    return false;
+
   pend = p + cof->raw_syment_count;
   while (p < pend)
     {