bfd/
[binutils-gdb.git] / bfd / cofflink.c
index dbe7fbf100f80526490a741b5d4c804c2cbbd678..19cb54fcce87f54e4820ca121b0cfa39fddadd49 100644 (file)
@@ -1,6 +1,6 @@
 /* COFF specific linker code.
-   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -27,6 +27,7 @@
 #include "libbfd.h"
 #include "coff/internal.h"
 #include "libcoff.h"
+#include "safe-ctype.h"
 
 static bfd_boolean coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info);
 static bfd_boolean coff_link_check_archive_element (bfd *abfd, struct bfd_link_info *info, bfd_boolean *pneeded);
@@ -95,7 +96,7 @@ _bfd_coff_link_hash_table_init (struct coff_link_hash_table *table,
                                                                   struct bfd_hash_table *,
                                                                   const char *))
 {
-  table->stab_info = NULL;
+  memset (&table->stab_info, 0, sizeof (table->stab_info));
   return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
 }
 
@@ -434,18 +435,19 @@ coff_link_add_symbols (bfd *abfd,
          if (obj_pe (abfd)
              && (classification == COFF_SYMBOL_GLOBAL
                  || classification == COFF_SYMBOL_PE_SECTION)
-             && section->comdat != NULL
+             && coff_section_data (abfd, section) != NULL
+             && coff_section_data (abfd, section)->comdat != NULL
              && strncmp (name, "??_", 3) == 0
-             && strcmp (name, section->comdat->name) == 0)
+             && strcmp (name, coff_section_data (abfd, section)->comdat->name) == 0)
            {
              if (*sym_hash == NULL)
                *sym_hash = coff_link_hash_lookup (coff_hash_table (info),
                                                   name, FALSE, copy, FALSE);
              if (*sym_hash != NULL
                  && (*sym_hash)->root.type == bfd_link_hash_defined
-                 && (*sym_hash)->root.u.def.section->comdat != NULL
-                 && strcmp ((*sym_hash)->root.u.def.section->comdat->name,
-                            section->comdat->name) == 0)
+                 && coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat != NULL
+                 && strcmp (coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat->name,
+                            coff_section_data (abfd, section)->comdat->name) == 0)
                addit = FALSE;
            }
 
@@ -502,9 +504,8 @@ coff_link_add_symbols (bfd *abfd,
                               && (BTYPE ((*sym_hash)->type) == T_NULL
                                   || BTYPE (sym.n_type) == T_NULL)))
                        (*_bfd_error_handler)
-                         (_("Warning: type of symbol `%s' changed from %d to %d in %s"),
-                          name, (*sym_hash)->type, sym.n_type,
-                          bfd_archive_filename (abfd));
+                         (_("Warning: type of symbol `%s' changed from %d to %d in %B"),
+                          abfd, name, (*sym_hash)->type, sym.n_type);
 
                      /* We don't want to change from a meaningful
                         base type to a null one, but if we know
@@ -550,8 +551,8 @@ coff_link_add_symbols (bfd *abfd,
                 For example, it won't help objdump.  This needs to be
                 done when we swap in the section header.  */
              BFD_ASSERT ((*sym_hash)->numaux == 1);
-             if (section->_raw_size == 0)
-               section->_raw_size = (*sym_hash)->aux[0].x_scn.x_scnlen;
+             if (section->size == 0)
+               section->size = (*sym_hash)->aux[0].x_scn.x_scnlen;
 
              /* FIXME: We could test whether the section sizes
                  matches the size in the aux entry, but apparently
@@ -582,7 +583,7 @@ coff_link_add_symbols (bfd *abfd,
          for (stab = abfd->sections; stab; stab = stab->next)
            if (strncmp (".stab", stab->name, 5) == 0
                && (!stab->name[5]
-                   || (stab->name[5] == '.' && isdigit (stab->name[6]))))
+                   || (stab->name[5] == '.' && ISDIGIT (stab->name[6]))))
            {
              struct coff_link_hash_table *table;
              struct coff_section_tdata *secdata
@@ -713,8 +714,10 @@ _bfd_coff_final_link (bfd *abfd,
              if (info->relocatable)
                o->reloc_count += sec->reloc_count;
 
-             if (sec->_raw_size > max_contents_size)
-               max_contents_size = sec->_raw_size;
+             if (sec->rawsize > max_contents_size)
+               max_contents_size = sec->rawsize;
+             if (sec->size > max_contents_size)
+               max_contents_size = sec->size;
              if (sec->lineno_count > max_lineno_count)
                max_lineno_count = sec->lineno_count;
              if (sec->reloc_count > max_reloc_count)
@@ -1079,7 +1082,7 @@ _bfd_coff_final_link (bfd *abfd,
     }
 
   /* If we have optimized stabs strings, output them.  */
-  if (coff_hash_table (info)->stab_info != NULL)
+  if (coff_hash_table (info)->stab_info.stabstr != NULL)
     {
       if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info))
        return FALSE;
@@ -1207,30 +1210,27 @@ process_embedded_commands (bfd *output_bfd,
   asection *sec = bfd_get_section_by_name (abfd, ".drectve");
   char *s;
   char *e;
-  char *copy;
+  bfd_byte *copy;
 
   if (!sec)
     return 1;
 
-  copy = bfd_malloc (sec->_raw_size);
-  if (!copy)
-    return 0;
-
-  if (! bfd_get_section_contents (abfd, sec, copy, (bfd_vma) 0, sec->_raw_size))
+  if (!bfd_malloc_and_get_section (abfd, sec, &copy))
     {
-      free (copy);
+      if (copy != NULL)
+       free (copy);
       return 0;
     }
-  e = copy + sec->_raw_size;
+  e = (char *) copy + sec->size;
 
-  for (s = copy;  s < e ; )
+  for (s = (char *) copy; s < e ; )
     {
-      if (s[0]!= '-')
+      if (s[0] != '-')
        {
          s++;
          continue;
        }
-      if (strncmp (s,"-attr", 5) == 0)
+      if (strncmp (s, "-attr", 5) == 0)
        {
          char *name;
          char *attribs;
@@ -1345,9 +1345,6 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
 {
   unsigned int n_tmask = coff_data (input_bfd)->local_n_tmask;
   unsigned int n_btshft = coff_data (input_bfd)->local_n_btshft;
-#if 0
-  unsigned int n_btmask = coff_data (input_bfd)->local_n_btmask;
-#endif
   bfd_boolean (*adjust_symndx)
     (bfd *, struct bfd_link_info *, bfd *, asection *,
      struct internal_reloc *, bfd_boolean *);
@@ -1976,7 +1973,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
                      auxp->x_file.x_n.x_offset = STRING_SIZE_SIZE + indx;
                    }
                }
-             else if (isymp->n_sclass != C_STAT || isymp->n_type != T_NULL)
+             else if ((isymp->n_sclass != C_STAT || isymp->n_type != T_NULL)
+                      && isymp->n_sclass != C_NT_WEAK)
                {
                  unsigned long indx;
 
@@ -2282,16 +2280,18 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
        /* This section was omitted from the link.  */
        continue;
 
+      if ((o->flags & SEC_LINKER_CREATED) != 0)
+       continue;
+
       if ((o->flags & SEC_HAS_CONTENTS) == 0
-         || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0))
+         || (o->size == 0 && (o->flags & SEC_RELOC) == 0))
        {
          if ((o->flags & SEC_RELOC) != 0
              && o->reloc_count != 0)
            {
-             ((*_bfd_error_handler)
-              (_("%s: relocs in section `%s', but it has no contents"),
-               bfd_archive_filename (input_bfd),
-               bfd_get_section_name (input_bfd, o)));
+             (*_bfd_error_handler)
+               (_("%B: relocs in section `%A', but it has no contents"),
+                input_bfd, o);
              bfd_set_error (bfd_error_no_contents);
              return FALSE;
            }
@@ -2304,8 +2304,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
        contents = secdata->contents;
       else
        {
-         if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
-                                         (file_ptr) 0, o->_raw_size))
+         bfd_size_type x = o->rawsize ? o->rawsize : o->size;
+         if (! bfd_get_section_contents (input_bfd, o, finfo->contents, 0, x))
            return FALSE;
          contents = finfo->contents;
        }
@@ -2430,10 +2430,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *finfo, bfd *input_bfd)
       if (secdata == NULL || secdata->stab_info == NULL)
        {
          file_ptr loc = o->output_offset * bfd_octets_per_byte (output_bfd);
-         bfd_size_type amt = (o->_cooked_size != 0
-                              ? o->_cooked_size : o->_raw_size);
          if (! bfd_set_section_contents (output_bfd, o->output_section,
-                                         contents, loc, amt))
+                                         contents, loc, o->size))
            return FALSE;
        }
       else
@@ -2564,7 +2562,7 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
       isym.n_sclass = C_STAT;
     }
 
-  /* When a weak symbol is not overriden by a strong one,
+  /* When a weak symbol is not overridden by a strong one,
      turn it into an external symbol when not building a
      shared or relocatable object.  */
   if (! finfo->info->shared
@@ -2615,9 +2613,7 @@ _bfd_coff_write_global_sym (struct coff_link_hash_entry *h, void *data)
          sec = h->root.u.def.section->output_section;
          if (sec != NULL)
            {
-             auxp->x_scn.x_scnlen = (sec->_cooked_size != 0
-                                     ? sec->_cooked_size
-                                     : sec->_raw_size);
+             auxp->x_scn.x_scnlen = sec->size;
 
              /* For PE, an overflow on the final link reportedly does
                  not matter.  FIXME: Why not?  */
@@ -2737,7 +2733,7 @@ _bfd_coff_reloc_link_order (bfd *output_bfd,
          abort ();
        case bfd_reloc_overflow:
          if (! ((*finfo->info->callbacks->reloc_overflow)
-                (finfo->info,
+                (finfo->info, NULL,
                  (link_order->type == bfd_section_reloc_link_order
                   ? bfd_section_name (output_bfd,
                                       link_order->u.reloc.p->u.section)
@@ -2862,8 +2858,7 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
               || (unsigned long) symndx >= obj_raw_syment_count (input_bfd))
        {
          (*_bfd_error_handler)
-           ("%s: illegal symbol index %ld in relocs",
-            bfd_archive_filename (input_bfd), symndx);
+           ("%B: illegal symbol index %ld in relocs", input_bfd, symndx);
          return FALSE;
        }
       else
@@ -2924,16 +2919,48 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
          if (h->root.type == bfd_link_hash_defined
              || h->root.type == bfd_link_hash_defweak)
            {
+             /* Defined weak symbols are a GNU extension. */
              asection *sec;
 
              sec = h->root.u.def.section;
              val = (h->root.u.def.value
                     + sec->output_section->vma
                     + sec->output_offset);
-             }
+           }
 
          else if (h->root.type == bfd_link_hash_undefweak)
-           val = 0;
+           {
+              if (h->class == C_NT_WEAK && h->numaux == 1)
+               {
+                 /* See _Microsoft Portable Executable and Common Object
+                     File Format Specification_, section 5.5.3.
+                    Note that weak symbols without aux records are a GNU
+                    extension.
+                    FIXME: All weak externals are treated as having
+                    characteristics IMAGE_WEAK_EXTERN_SEARCH_LIBRARY (2).
+                    There are no known uses of the other two types of
+                    weak externals.  */
+                 asection *sec;
+                 struct coff_link_hash_entry *h2 =
+                   input_bfd->tdata.coff_obj_data->sym_hashes[
+                   h->aux->x_sym.x_tagndx.l];
+
+                 if (!h2 || h2->root.type == bfd_link_hash_undefined)
+                   {
+                     sec = bfd_abs_section_ptr;
+                     val = 0;
+                   }
+                 else
+                   {
+                     sec = h2->root.u.def.section;
+                     val = h2->root.u.def.value
+                       + sec->output_section->vma + sec->output_offset;
+                   }
+               }
+             else
+                /* This is a GNU extension.  */
+               val = 0;
+           }
 
          else if (! info->relocatable)
            {
@@ -2983,10 +3010,8 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
          break;
        case bfd_reloc_outofrange:
          (*_bfd_error_handler)
-           (_("%s: bad reloc address 0x%lx in section `%s'"),
-            bfd_archive_filename (input_bfd),
-            (unsigned long) rel->r_vaddr,
-            bfd_get_section_name (input_bfd, input_section));
+           (_("%B: bad reloc address 0x%lx in section `%A'"),
+            input_bfd, input_section, (unsigned long) rel->r_vaddr);
          return FALSE;
        case bfd_reloc_overflow:
          {
@@ -2996,7 +3021,7 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
            if (symndx == -1)
              name = "*ABS*";
            else if (h != NULL)
-             name = h->root.root.string;
+             name = NULL;
            else
              {
                name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
@@ -3005,8 +3030,9 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd,
              }
 
            if (! ((*info->callbacks->reloc_overflow)
-                  (info, name, howto->name, (bfd_vma) 0, input_bfd,
-                   input_section, rel->r_vaddr - input_section->vma)))
+                  (info, (h ? &h->root : NULL), name, howto->name,
+                   (bfd_vma) 0, input_bfd, input_section,
+                   rel->r_vaddr - input_section->vma)))
              return FALSE;
          }
        }